上一篇《Request 接收參數亂碼原理解析一:服務器端解碼原理》,分析了服務器端解碼的過程,那麼瀏覽器是根據什麼編碼的呢?javascript
1. 瀏覽器解碼html
瀏覽器根據服務器頁面響應Header中的「Content-Type: text/html; charset=gb2312」解碼。修改web.config中「responseEncoding=utf-8」,發現服務器頁面響應Header變成了「Content-Type: text/html; charset=utf8」。java
<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。jquery
protected void Page_Load(object sender, EventArgs e) { Response.Charset = "utf-8"; }
2. 提交表單時的編碼web
頁面Get或者Post提交form表單數據時,會對錶單中的中文進行編碼,而編碼方式是由服務器頁面響應Header中的「Content-Type: text/html; charset=gb2312」肯定的(和瀏覽器解碼方式一致)。示例代碼:ajax
<%@ 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編碼 app
在瀏覽器中輸入地址: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編碼。