推荐:解决asp.net中的各种乱码问题

发布时间:2020-06-30编辑:脚本学堂
本文介绍asp.net中各种乱码问题的解决方法,供大家学习参考。

下面我来解释前面不建议使用的另外的一些方法的原因:
1. Server.UrlEncode: 这个方法其实也是调用HttpUtility.UrlEncode,只是它会尽量使用Response.ContentEncoding所表示的编码格式, 然而HttpUtility.UrlEncode(str)总是会使用UTF-8编码,如果你不希望被字符编码纠缠,那就应该放弃Server.UrlEncode , 毕竟UTF-8编码才是更好的选择。
2. 虽然System.Uri的那二个编码方法,也能实现我们需要的URL编码任务, 但是,当ASP.NET在填充Request.QueryString, Request.Form时,使用的解码方法是HttpUtility.UrlDecode, 因此,如果你执意选择使用System.Uri的相关的编码方法,显然就不能与解码方法匹配,后果如何就难说了。

正确的URL编码方式的总结

由于编码函数(方法)较多,而且又比较重要,我认为有必要再做个总结。

一个完整的URL可以简单地认为包含二个部分:文件路径(含目录) 和 查询参数(QueryString)
在编码时,一定要分开处理。
编码文件路径时,应该选择 encodeURI,HttpUtility.UrlPathEncode 。
编码查询参数时,应该选择 encodeURIComponent,HttpUtility.UrlEncode,而且拼接方式应该是:Encode(key) + "=" + Encode(value)

绝对不能先把整个URL(包含查询参数)拼接起来了,再来考虑该选择哪个编码方法。
再说一遍:在JavaScript中使用escape肯定是错误的。

回到顶部
彻底解决encodeURIComponent()与GB2312乱码问题

前面我建议在JavaScript中使用encodeURIComponent()来处理提交数据, 然而encodeURIComponent()在编码字符时,使用的是UTF-8编码。 也正因为这个原因,有人可能会说:我的网站使用的编码方式是gb2312 !
 

复制代码 代码如下:
<globalization requestEncoding="gb2312" responseEncoding="gb2312" />

对于这个回答,我有时实在不想再说下去了:你就不能把网站的编码改成UTF-8吗?

现在好了,我设计了一种方法,可以解决在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显示的下载对话框也是我期待的样子:
aspnet-encode-5
遗憾的是,在我的IE8中是这样的:
aspnet-encode-6

对于这个乱码问题,我们需要把代码做一点修改:
 

复制代码 代码如下:
string downloadName = "ClownFish性能测试结果.xlsx";
if( context.Request.Browser.Browser == "IE" )
    downloadName = HttpUtility.UrlPathEncode(downloadName);


此时IE显示的文件名就不是乱码了。

说明:我的机器环境是 Windows Server 2003 SP2, 用于测试的浏览器版本分别为:
aspnet-encode-7

回到顶部
多语言数据的乱码问题

现在还有一种乱码问题是:同一个程序供多种不同字符集(语言)的用户在使用。
例如:程序是简体中文的,此时,繁体中文的用户无法保存繁体汉字(就算简体汉字能正常显示)。

当发现这种现象时,需要检查一下数据库的字段类型,是否是Unicode或者UTF-8, 因为当数据字段的字符集不支持多种语言时,乱码问题必定产生。

我建议在使用SQL SERVER时,保存文字的字段都使用N开头的类型, 如:nvarchar, nchar,除非明确知道要保存邮政编码或者md5值,才有必要使用char(xxx)这种数据类型。 类似的,在mysql中,我建议使用UTF-8

回到顶部
乱码问题的总结
ASP.NET的乱码问题一般与二个因素有关:
1. 选择了不恰当的字符编码,如:gb2312
2. 选择了不正确的URL编码方法,如:escape()

因此,解决方案其实也不难:
1. 字符编码选择 utf-8 ,包含文件编码,请求/响应编码,数据库字段类型。
2. URL编码方法选择encodeURIComponent,再次强烈推荐直接使用JQuery

我一直认为:正确的方法可以让我在无形中避开许多问题。
如果你还为乱码问题而烦恼,我建议你先想想你是否选择了不正确的编码(方法)。
点这里下载本文示例代码
原文链接:http://www.cnblogs.com/fish-li/archive/2012/10/14/2723631.html