1

I'm using UnityHTTP (https://github.com/andyburke/UnityHTTP) to call a REST API ( KiiCloud http://www.kii.com ) and it works great but I want to get rid of the 3rd party library if possible and use Unity's WWW and WWWForm to achieve the same.

Here's the code that uses UnityHTTP that works fine:

public static void RunServerExtension (string appId, string appKey, string endpoint, string kii_access_token, string msg)
{
    Hashtable data = new Hashtable();
    // Add json fields with values here (use as dictionary)
    data.Add("message", msg);

    // When you pass a Hashtable as the third argument, we assume you want it send as JSON-encoded
    // data.  We'll encode it to JSON for you and set the Content-Type header to application/json
    HTTP.Request myRequest = new HTTP.Request( "post", "https://api.kii.com/api/apps/" + appId + "/server-code/versions/current/" + endpoint, data);

    myRequest.AddHeader("x-kii-appid", appId);
    myRequest.AddHeader("x-kii-appkey", appKey);
    if(kii_access_token != null)
            theRequest.AddHeader("Authorization", "Bearer " + kii_access_token);

    myRequest.Send( ( request ) => {
        // we provide Object and Array convenience methods that attempt to parse the response as JSON
        // if the response cannot be parsed, we will return null
        // note that if you want to send json that isn't either an object ({...}) or an array ([...])
        // that you should use JSON.JsonDecode directly on the response.Text, Object and Array are
        // only provided for convenience
        Hashtable result = request.response.Object;
        if ( result == null )
        {
            Debug.LogWarning( "Could not parse JSON response!" );
            return;
        }
        Debug.Log ("Got response");
        Debug.Log(request.response.Text);   
    });
}

So the above works just fine but when I switch to WWWForm in this way:

public static WWW RunServerExtension (string appId, string appKey, string endpoint, string kii_access_token, string msg)
{
    WWWForm form = new WWWForm();
    Hashtable headers = form.headers;
    headers["Content-Type"] = "application/json";
    headers["x-kii-appid"] = appId;
    headers["x-kii-appkey"] = appKey;
    if(kii_access_token != null)
        headers["Authorization"] = "Bearer " + kii_access_token;
    form.AddField("message", msg);
    return new WWW("https://api.kii.com/api/apps/" + appId + "/server-code/versions/current/" + endpoint, form.data, headers);
}

private IEnumerator WaitForRequest(WWW www)
{
    yield return www;

    // check for errors
    if (www.error == null)
    {
        Debug.Log("WWW Ok!: " + www.text);
    } else {
        Debug.Log("WWW Error: "+ www.error);
    }    
}

I get a BAD REQUEST on the server side (meaning the request is malformed, not what the server was expecting). Note that the headers must be passed as parameter otherwise the server complains about missing headers.

I suspected this might be related to the fact that the server expects JSON data so I converted the message to JSON using UnityHTTP JSON class (you can use just that isolated class for JSON encoding/decoding) https://github.com/andyburke/UnityHTTP/blob/master/external/JSON.cs so this method passes {"message":"This is echoed!!"} as data:

public static WWW RunServerExtension (string appId, string appKey, string endpoint, string kii_access_token, string msg)
{
    WWWForm form = new WWWForm();
    Hashtable headers = form.headers;
    headers["Content-Type"] = "application/json";
    headers["x-kii-appid"] = appId;
    headers["x-kii-appkey"] = appKey;
    if(kii_access_token != null)
        headers["Authorization"] = "Bearer " + kii_access_token;
    Hashtable data = new Hashtable();
    data["message"] = msg;
    byte[] bytes = GetBytes(JSON.JsonEncode(data));
    return new WWW("https://api.kii.com/api/apps/" + appId + "/server-code/versions/current/" + endpoint, bytes, headers);
}

static byte[] GetBytes(string str)
{
    byte[] bytes = new byte[str.Length * sizeof(char)];
    System.Buffer.BlockCopy(str.ToCharArray(), 0, bytes, 0, bytes.Length);
    return bytes;
}

But still the same BAD REQUEST. Do you see why this could be failing? Why UnityHTTP works?

4

1 回答 1

1

正如我在评论中提到的:C# 将所有字符串转换为 UTF-16。如果您的网络服务器需要不同的编码,那么简单地逐字传递字节不会产生好的结果。

JSON 通常以 UTF-8 编码,但最好是 API 明确指定其输入/输出编码。

我今天花了更多的时间。如果您检查 UnityHTTP 的源代码,您可以看到他们的 Hashtable 构造函数将 JSON 编码为 UTF-8

    this.bytes = Encoding.UTF8.GetBytes( JSON.JsonEncode( data ) );

您的代码不会更改字符串的编码,这意味着您发送了错误的字节。

于 2014-02-19T21:22:02.360 回答