关于unity3d:使用WWWForm的格式错误的HTTP帖子

Malformed HTTP post using WWWForm

我正在使用UnityHTTP(https://github.com/andyburke/UnityHTTP)来调用REST API(KiiCloud http://www.kii.com),它的效果很好,但是我想摆脱第3方库如果可能的话,并使用Unity的WWW和WWWForm实现相同的目的。

这是使用UnityHTTP的代码,可以正常工作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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);  
    });
}

所以上面的工作很好,但是当我以这种方式切换到WWWForm时:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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);
    }    
}

我在服务器端收到错误请求(意味着请求格式错误,而不是服务器期望的内容)。请注意,必须将标头作为参数传递,否则服务器会抱怨缺少标头。

我怀疑这可能与服务器需要JSON数据有关,因此我使用UnityHTTP JSON类(您可以仅使用该隔离的类进行JSON编码/解码)将消息转换为JSON https://github.com/andyburke/ UnityHTTP / blob / master / external / JSON.cs,因此此方法将{" message":" This is echoed !!"}作为数据传递:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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;
}

但是仍然有相同的错误请求。您知道为什么这可能会失败吗?为什么UnityHTTP可以工作?


正如我在评论中提到的:C#将所有字符串转换为UTF-16。 如果您的网络服务器期望使用不同的编码,则仅逐字传递字节将不会产生良好的结果。

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

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

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

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