上一篇《Request 接收參數亂碼原理解析一:服務器端解碼原理》,分析了服務器端解碼的過程,那么瀏覽器是根據什么編碼的呢?
1. 瀏覽器解碼
瀏覽器根據服務器頁面響應Header中的“Content-Type: text/html; charset=gb2312”解碼。修改web.config中“responseEncoding=utf-8”,發現服務器頁面響應Header變成了“Content-Type: text/html; charset=utf8”。
<system.web> <globalization requestEncoding="gb2312" responseEncoding="gb2312"/> </system.web>
除了web.config中的globalization結點可以影響charset,修改頁面Page_Load(配置文件仍為gb2312),發現頁面charset輸出也變成了utf-8,但同時也發現頁面中的中文成了亂碼。微軟對Response.Charset的解釋是獲取或設置輸出流的HTTP字符集,為什么會出現亂碼?個人猜測可能整個頁面是按照web.config中指定GB2312編碼的,但輸出的時候將字符集強制變成了utf-8。
protected void Page_Load(object sender, EventArgs e) { Response.Charset = "utf-8"; }
2. 提交表單時的編碼
頁面Get或者Post提交form表單數據時,會對表單中的中文進行編碼,而編碼方式是由服務器頁面響應Header中的“Content-Type: text/html; charset=gb2312”確定的(和瀏覽器解碼方式一致)。示例代碼:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="EncodeTest.aspx.cs" Inherits="Com.Shizi.Time8.UI.Test.WebTest.EncodeTest" %> <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>頁面編碼測試</title> <script type="text/javascript" src="Scripts/jquery-2.1.1.min.js"></script> </head> <body> <form id="form1" action="EncodeTest.aspx" method="post"> <div> <input type="text" name="name" id="name" value="北京" /> </div> <div> <input type="submit" name="btnSumbit" value="sumbmit" /></div> </form> <div> <input type="button" name="btnAjaxPost" value="AJaxPost提交" onclick="AjaxPost()" /> <input type="button" name="btnAjaxGet" value="AJaxGet提交" onclick="AjaxGet()" /></div> <div id="divMessage" style="color:red"></div> <script type="text/javascript"> function AjaxGet() { $.ajax({ type: "GET", url: "EncodeTest.aspx?namequery=" + $("#name").val(), data: { name: $("#name").val(), action: "ajax", methodtype: "get" }, success: function (data) { $("#divMessage").html(data); } }); } function AjaxPost() { $.ajax({ type: "POST", url: "EncodeTest.aspx?namequery=" + $("#name").val(), data: { name: $("#name").val(), action: "ajax", methodtype: "post" }, success: function (data) { $("#divMessage").text(data); } }); } </script> </body> </html>
不管get提交還是post提交,input控件全部都進行了GB2312編碼,提交的數據為“name=%B1%B1%BE%A9&btnSumbit=sumbmit”。修改web.config中“responseEncoding=utf-8”,發現服務器頁面響應Header中的“Content-Type: text/html; charset=utf8”,再次提交表單時編碼已經成了utf-8,內容變為“name=%E5%8C%97%E4%BA%AC&btnSumbit=sumbmit”。
觀察發現,不管get提交還是post提交,HTTP請求中並沒有指定服務器端的解碼方式,服務器端解碼還是根據服務器配置獲取的,本例中是用GB2312解碼的。
3. 瀏覽器地址欄Url編碼
在瀏覽器中輸入地址:http://localhost:52443/EncodeTest.aspx?name=北京,“name=北京”的編碼方式隨瀏覽器不同而不同,IE11編碼方式為GBK,服務器用GB2312解碼正確;Firefox34.0編碼方式為utf-8,服務器GB2312解碼亂碼。URL中的編碼依賴於瀏覽器,開發中不建議使用,一些地址鏈接含有中文時,建議在生成鏈接時,對中文指定編碼方式編碼。
4. JQuery中的AJax提交
JQuery是一款優秀的js框架,被廣泛使用,但通過AJax提交數據時,卻容易出現亂碼。通過測試和分析JQuery源碼,AJax請求時,推薦方式為:
1)POST請求:參數放到data中,無需對參數值編碼,JQuery在構造HTTP請求時,會調用js的函數encodeURIComponent()對data中的鍵值對分別進行utf-8編碼,服務器用utf-8解碼。url中對應的就是url地址,不能含有參數。
即使服務器Globalization結點配置的GB2312解碼,Request.Form["xxx"]也會用utf-8解碼,因為AJax的post請求中在HTTP頭添加了代碼“Content-Type: text/html; charset=utf8”,告訴服務器用utf-8解碼,達到編碼和解碼一致的目的。這點可能和我們平時想的不一樣,整站配置為GB2312編碼的站點,竟然AJax的post請求都是用的utf-8編碼!

// 拼裝參數 if ( s.data && s.processData && typeof s.data !== "string" ) { s.data = jQuery.param( s.data, s.traditional ); } // 如果有post data的話,設置請求Header if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) { jqXHR.setRequestHeader( "Content-Type", s.contentType ); } // key/values into a query string jQuery.param = function( a, traditional ) { var prefix, s = [], add = function( key, value ) { // If value is a function, invoke it and return its value value = jQuery.isFunction( value ) ? value() : ( value == null ? "" : value ); s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value ); }; // Set traditional to true for jQuery <= 1.3.2 behavior. if ( traditional === undefined ) { traditional = jQuery.ajaxSettings && jQuery.ajaxSettings.traditional; } // If an array was passed in, assume that it is an array of form elements. if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) { // Serialize the form elements jQuery.each( a, function() { add( this.name, this.value ); }); } else { // If traditional, encode the "old" way (the way 1.3.2 or older // did it), otherwise encode params recursively. for ( prefix in a ) { buildParams( prefix, a[ prefix ], traditional, add ); } } // Return the resulting serialization return s.join( "&" ).replace( r20, "+" ); };
2)GET請求:參數放在Url中,並按照和服務器一致的編碼方式編碼,如服務器配置的Globalization結點為UTF-8,則將參數值用UTF-8編碼,可以調用函數encodeURIComponent();如果服務器配置為GB2312,則將參數用GB2312編碼,可以調用escape()。Get和Post請求的一大差別是,GET請求不會改變請求的Header,Request.QueyString["xxx"]解碼用的是Globalization指定的編碼。
如下面的代碼,在配置為GB2312編碼的站點運行正常,無亂碼,其中post請求是utf-8解碼,get請求是gb2312解碼。
function AjaxGet() { $.ajax({ type: "GET", url: "EncodeTest.aspx?namequery=" + escape($("#name").val()), success: function (data) { $("#divMessage").html(data); } }); } function AjaxPost() { $.ajax({ type: "POST", url: "EncodeTest.aspx", data: { name: $("#name").val(), action: "ajax", methodtype: "post" }, success: function (data) { $("#divMessage").text(data); } }); }
默認情況下,JQuery的AJax方法通過post提交數據,編碼都是用的utf-8,通過Header指定服務器解碼方式也為utf-8,但某些特殊情況下可能想服務器用gb2312解碼(現在想來應該不需要這種場景,因為本身就不大合理,當時可能在某些不大合理的前提下確實需要來着,還不停的百度),網上查找資料是說AJax時,添加屬性“contentType: "application/x-www-form-urlencoded; charset=utf-8",”個人測試IE下生效了,服務器變成了GB2312解碼,但火狐下未生效,原因未知,單步跟蹤了代碼都執行了,沒啥問題。
參考:Asp.net中Response.Charset 與Response.ContentEncoding區別,charset 和character encoding,深入淺出URL編碼。