解决服务器返回JSON数据中文乱码问题

时间:2023-02-10 11:54:44

        还是编码的问题.

        下午试了一下谷歌搜索的 REST 服务, 接口是 "http://ajax.googleapis.com/ajax/services/search/web?v=1.0&q=<search item>, 过程也很简单: 将你要搜索的内容经过 UrlEncode 之后代替<search item>, 然后发出一个 GET 请求, 就应该得到该搜索内容的 JSON 数据. 比如我搜索 "Create Chen", 在浏览器中可以看到返回如下数据:

{"responseData": {"results":[{"GsearchResultClass":"GwebSearch","unescapedUrl":"http://www.cnblogs.com/technology/","url":"http://www.cnblogs.com/technology/","visibleUrl":"www.cnblogs.com","cacheUrl":"http://www.google.com/search?q\u003dcache:wymiOeNCuYMJ:www.cnblogs.com","title":"\u003cb\u003eCreate Chen\u003c/b\u003e - 博客园","titleNoFormatting":"Create Chen - 博客园","content":"posted @ 2011-05-26 15:57 \u003cb\u003eCreate Chen\u003c/b\u003e 阅读(1206) | 评论(30) | 编辑 \u003cb\u003e...\u003c/b\u003e posted @ 2011-05-22 20:49 \u003cb\u003eCreate Chen\u003c/b\u003e 阅读(1781) | 评论(26) | 编辑

...省略以下内容...

        展示上一段的目的是为了说明在浏览器里, 数据包含中文的话, 还是显示正常的, 原因很简单: 我浏览器设置的默认编码就是 Unicode(UTF-8), 当然能正确显示中文.

        为了更好的展示数据, 我按照<Programming ASP.NET 3.5>里将在程序中获得的 JSON 数据序列化了一下, 没想到总是在序列化的时候出错, 只有搜索结果不包含中文的时候才运行正常. 代码如下:

//...
//GoogleSearchResponse的一些构造
//...

protected void btnSearch_Click(object sender, EventArgs e)
{
    WebClient wc = new WebClient();
    Response.Write(wc.Encoding.ToString());
    wc.Headers.Add(HttpRequestHeader.Referer, Request.Url.ToString());
    string url = string.Format("http://ajax.googleapis.com/ajax/services/search/web?v=1.0&q={0}",
        Server.UrlEncode(txtSearchFor.Text));
    var json = wc.DownloadString(url);
    GoogleSearchResponse sechResponse = null;
    using (MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(json)))
    {
        DataContractJsonSerializer jsonSerializer = new DataContractJsonSerializer(typeof(GoogleSearchResponse));
        sechResponse = jsonSerializer.ReadObject(ms) as GoogleSearchResponse;
    }
    StringBuilder sb = new StringBuilder();
    foreach (GoogleResult res in sechResponse.responseData.results)
    {
        sb.AppendFormat("<a href='{0}'>{1}</a><br />", res.unescapedUrl, res.title);
    }
    lblResults.Text = sb.ToString();
}

        经过调试发现在代码高亮的那一行, json字符串已经是乱码了. 因此我查看了 WebClient 的 DownloadString 方法:

        This method retrieves the specified resource. After it downloads the resource, the method uses the encoding specified in the Encoding property to convert the resource to a String. This method blocks while downloading the resource. To download a resource and continue executing while waiting for the server's response, use one of the DownloadStringAsync methods.

        前面两句说在下载到资源 (应该是 Byte[]) 后, 这个方法将会调用默认的编码方式将资源转化成 String. 好吧, 我来看看默认的编码方式是不是 UTF-8. 往往默认的编码方式是由操作系统和地区决定的, 在我的机器上测试后得知默认的编码方式不是 UTF-8, 是 System.Text.DBCSCodePageEncoding, 尽管编码方式不是 UTF-8, 但除了中文集字符, 这种编码方式确实还能识别出 Unicode 类型的编码, 前提是文件开头要有 BOM 信息, 关于能从 BOM 中获得哪些信息, 如下:

Unicode         0xFF, 0xFE
BE-Unicode    0xFE, 0xFF
UTF8        0xEF, 0xBB, 0xBF

        就是这样的一个对应关系, 但我发现服务器返回的 JSON 数据并没有这样的 BOM 信息:

解决服务器返回JSON数据中文乱码问题

        因此, 我需要在程序中设置一下 WebClient 的 Encoding 属性, 将它设为 Encoding.UTF8, 运行正常.

解决服务器返回JSON数据中文乱码问题

        但回过头来看看, 程序似乎在 DownloadString 方法中将下载到的 Byte[] 转成一个 String, 紧接着又将这个 String 转换成 Byte[] 存进内存中, 可以直接调用 DownloadData 方法的, 将 DownloadData 方法下载到的数据直接存储到内存中, 然后再做进一步的序列化处理, 这样就省去了两次类型转换的操作.

        关于编码, 前几天还看到了一个笑话, 也不知道是真的还是假的:

        以Windows中文版为例。从英文版移植到中文版,并不只是翻译菜单那么简单,许多源代码都得重新改写。比如Word里打完一行字会自动换行,可英文是单字节的,中文却是双字节,一个“好”字,就很可能“女”在上一行末尾,“子”却到了下一行开头。——唐骏 <我的成功可以复制> P89