还是编码的问题.
下午试了一下谷歌搜索的 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 信息:
因此, 我需要在程序中设置一下 WebClient 的 Encoding 属性, 将它设为 Encoding.UTF8, 运行正常.
但回过头来看看, 程序似乎在 DownloadString 方法中将下载到的 Byte[] 转成一个 String, 紧接着又将这个 String 转换成 Byte[] 存进内存中, 可以直接调用 DownloadData 方法的, 将 DownloadData 方法下载到的数据直接存储到内存中, 然后再做进一步的序列化处理, 这样就省去了两次类型转换的操作.
关于编码, 前几天还看到了一个笑话, 也不知道是真的还是假的:
以Windows中文版为例。从英文版移植到中文版,并不只是翻译菜单那么简单,许多源代码都得重新改写。比如Word里打完一行字会自动换行,可英文是单字节的,中文却是双字节,一个“好”字,就很可能“女”在上一行末尾,“子”却到了下一行开头。——唐骏 <我的成功可以复制> P89