从服务器解析UTF8 JSON响应

时间:2013-08-04 12:50:45

标签: c# .net json http utf-8

我正面临一个从我的服务器解析JSON响应的奇怪问题。在过去几个月以这种方式获得响应(使用Content-Type:text / html)时,它一直运行良好:

string response = "";
using (var client = new System.Net.Http.HttpClient())
{
    var postData = new System.Net.Http.FormUrlEncodedContent(data);
    var clientResult = await client.PostAsync(url, postData);
    if(clientResult.IsSuccessStatusCode)
    {
        response = await clientResult.Content.ReadAsStringAsync();
    }
}
//Parse the response to a JObject...

但是当收到 Content-Type:text / html的回复时; charset = utf8 会抛出内容类型无效的异常。

Exception message: The character set provided in ContentType is invalid. Cannot read content as string using an invalid character set.

所以我改变了这个:

response = await clientResult.Content.ReadAsStringAsync();

到此:

var raw_response = await clientResult.Content.ReadAsByteArrayAsync();
response = Encoding.UTF8.GetString(raw_response, 0, raw_response.Length);

现在我可以在没有异常的情况下获得响应,但在解析它时,它会抛出一个解析异常。调试时我得到了这个:(为了测试目的,我将响应更改为较短的一个)

var r1 = await clientResult.Content.ReadAsStringAsync();
var r2 = Encoding.UTF8.GetString(await clientResult.Content.ReadAsByteArrayAsync(), 0, raw_response.Length);
System.Diagnostics.Debug.WriteLine("Length: {0} - {1}", r1.Length, r1);
System.Diagnostics.Debug.WriteLine("Length: {0} - {1}", r2.Length, r2);

//Output
Length: 38 - {"version":1,"specialword":"C\u00e3o"}
Length: 39 - {"version":1,"specialword":"C\u00e3o"}

JSON响应格式在两种情况下都是正确的,但长度不同,我无法弄清楚原因。将此复制到记事本++以识别隐藏的字符时,无处可见。

Length: 38 - {"version":1,"specialword":"C\u00e3o"}
Length: 39 - ?{"version":1,"specialword":"C\u00e3o"}

这个显然抛出了解析异常,但我不知道为什么会导致Encoding.UTF8.GetString

在过去的几个小时里,我一直在与此斗争,我真的需要一些帮助。

1 个答案:

答案 0 :(得分:8)

好吧,我很惊讶你得到了那种行为,我原本希望Encoding.UTF8.GetString为你处理这个问题。

您所看到的,字符值0xFEFF是字节顺序标记(“BOM”)。在UTF-8中不需要BOM,因为字节顺序不是可变的,但允许的,作为以下文本编码为UTF-8的标记。 (实际的字节序列是EF BB BF,但是当它以UTF-8解码时,它变为代码点FEFF。)

如果您创建自己的UTF8Encoding instance,您可以告诉它是否包含或排除BOM。 (我想我错了,它可能只能控制编码时是否包含一个。)

或者,您可以明确地测试并删除BOM(如果存在),例如:

var r2 = Encoding.UTF8.GetString(await clientResult.Content.ReadAsByteArrayAsync(), 0, raw_response.Length);
if (r2[0] == '\uFEFF') {
    r2 = r2.Substring(1);
}