现在好了,我设计了一种方法,可以解决在GB1212编码的网站中使用encodeURIComponent(), 这个方法的设计思路比较直接:既然encodeURIComponent()是使用UTF-8编码, 那么,我们是不是只要告诉服务端,客户端提交的数据是UTF-8编码的,此时服务端只要识别后,按照UTF-8编码来解码,问题就解决了。
理清了思路,代码其实很简单。首先来看客户端的代码。
$.ajax({ // 注意下面这行代码,它为请求添加一个自定义请求头 beforeSend: function(xhr) { xhr.setRequestHeader("x-charset", "utf-8"); }, url: "/TestParam.ashx", type: "GET", cache: false, data: { id: 2, name: "fish li + is me.", tel: "~!@#$%^&*()_+-=<>?|", "x?x!x&x": "aa=2&bb=3&cc=汉字。", // 特殊的键名,值内容也特殊。 encoding: "见鬼去吧。?& :)", 中文键名: "大明王朝1368" }, success: function(responseText) { $("#divResult").html(responseText); } });
注意:在原来的基础上,我只加了一行代码:
beforeSend: function(xhr) { xhr.setRequestHeader("x-charset", "utf-8"); },
再来看服务端代码。我写了一个HttpModule来统一处理这个问题。
public class ContentEncodingModule : IHttpModule { public void Init(HttpApplication app) { app.BeginRequest += new EventHandler(app_BeginRequest); } void app_BeginRequest(object sender, EventArgs e) { HttpApplication app = (HttpApplication)sender; HttpWorkerRequest request = (((IServiceProvider)app.Context) .GetService(typeof(HttpWorkerRequest)) as HttpWorkerRequest); // 注意:我并没有使用 app.Request.Headers["x-charset"] // 因为:绝大部分程序不访问它,它将一直保持是 null, // 如果我此时该问这个集合,会导致填充它。 // 我认为填充Headers集合比我下面的调用的成本要高很多, // 所以,直接通过HttpWorkerRequest读取请求头对性能的损耗会最小。 string charset = request.GetUnknownRequestHeader("x-charset"); if( string.Compare(charset, "utf-8", StringComparison.OrdinalIgnoreCase) == 0 ) // ASP.NET在填充QueryString,Form时,会访问Request.ContentEncoding做为解码时使用的字符编码 app.Request.ContentEncoding = System.Text.Encoding.UTF8; }
改造后的结果是:除非客户端明确添加"x-charset"请求头,否则还是按原来的方式处理,对于服务端代码来说,完全不用修改。
说明:
1. 如果网站的提交全部采用JQuery,也可以统一设置,这是JQuery支持的功能。
2. 如果使用JQuery1.5以上版本,也可以写成:headers: {"x-charset" : "utf-8"}
3. 就算以后网站使用UTF-8编码,所有代码不需要做任何修改。
Cookie乱码问题
前段时间,有人在博客的评论中问我:asp.net服务器端写中文cookie,js客户端读取时乱码。
其实这个问题还是比较好解决的,方法是:写Cookie时用HttpUtility.UrlEncode编码,然后在客户端使用decodeURIComponent把内容转回来就可以了。 在此,我推荐使用jquery.cookie.js这个插件来读写Cookie。 示例代码如下(前端):
$(function() { var cookie = $.cookie("TestJsRead"); $("#cookieValue").text(cookie); });
服务端代码:
cookie = new HttpCookie("TestJsRead", HttpUtility.UrlEncode("大明王朝1368")); Response.Cookies.Add(cookie);
下载文件名乱码问题
有时我们需要在程序运行时动态的创建文件,并让用户下载这个在运行时产生的文件, 然而,有时候用户会要求程序能生成一个默认的文件名,方便他们保存。 此时,我们只需要设置Content-Disposition这个响应头,并给一个默认的文件名就可以了。
一般说来,我们只要让默认的下载文件名是英文及数字,问题永远不会出现, 但是,有时候用户可能要求默认的文件中包含汉字, 最终,问题也随之发生了。 请看下面的代码:
public void ProcessRequest(HttpContext context) { byte[] fileContent = GetFileContent(); context.Response.ContentType = "application/octet-stream"; string downloadName = "ClownFish性能测试结果.xlsx"; string headerValue = string.Format("attachment; filename=\"{0}\"", downloadName); context.Response.AddHeader("Content-Disposition", headerValue); context.Response.OutputStream.Write(fileContent, 0, fileContent.Length); }
这段代码在我的FireFox, Opera, Safari, Chrome都能正常运行,其中FireFox显示的下载对话框也是我期待的样子:
遗憾的是,在我的IE8中是这样的:
对于这个乱码问题,我们需要把代码做一点修改:
string downloadName = "ClownFish性能测试结果.xlsx"; if( context.Request.Browser.Browser == "IE" ) downloadName = HttpUtility.UrlPathEncode(downloadName);
此时IE显示的文件名就不是乱码了。
说明:我的机器环境是 Windows Server 2003 SP2, 用于测试的浏览器版本分别为:
多语言数据的乱码问题