Request 接收参数乱码原理解析
起因:
今天早上被同事問了一個(gè)問題:說接收到的參數(shù)是亂碼,讓我?guī)椭鉀Q一下。?
?
實(shí)際情景:
同事負(fù)責(zé)的平臺(tái)是Ext.js框架搭建的,web.config配置文件里配置了全局為“GB2312”編碼:
<globalization?requestEncoding="gb2312"?responseEncoding="gb2312"?fileEncoding="gb2312"?culture="zh-CN"/>
當(dāng)前臺(tái)提交“中文文字”時(shí),后臺(tái)用Request.QueryString["xxx"]接收到的是亂碼。
無論用System.Web.HttpUtility.UrlDecode("xxx","編碼類型")怎么解碼都無效。
?
原理說明:
1:首先確定的是:客戶端的url參數(shù)在提交時(shí),Ext.js會(huì)對(duì)其編碼再提交,而客戶端的編碼默認(rèn)是utf-8編碼
客戶端默認(rèn)有三種編碼函數(shù):escape()?encodeURI()?encodeURIComponent()?
2:那為什么用Request.QueryString["xxx"]接收參數(shù)時(shí),收到的會(huì)是亂碼?
為此,我們必須解開Request.QueryString的原始處理邏輯過程?
我們步步反編繹,
2.1:看QueryString屬性的代碼:
Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/-->public NameValueCollection QueryString {get{if (this._queryString == null){this._queryString = new HttpValueCollection();if (this._wr != null){this.FillInQueryStringCollection();//重點(diǎn)代碼切入點(diǎn)}this._queryString.MakeReadOnly();}if (this._flags[1]){this._flags.Clear(1);ValidateNameValueCollection(this._queryString, "Request.QueryString");}return this._queryString;} }2.2:切入?FillInQueryStringCollection()方法
private void FillInQueryStringCollection() {byte[] queryStringBytes = this.QueryStringBytes;if (queryStringBytes != null){if (queryStringBytes.Length != 0){this._queryString.FillFromEncodedBytes(queryStringBytes, this.QueryStringEncoding);}}//上面是對(duì)流字節(jié)的處理,即文件上傳之類的。else if (!string.IsNullOrEmpty(this.QueryStringText)){//下面這句是對(duì)普通文件提交的處理:FillFromString是個(gè)切入點(diǎn),編碼切入點(diǎn)是:this.QueryStringEncodingthis._queryString.FillFromString(this.QueryStringText, true, this.QueryStringEncoding);} }2.3:切入:QueryStringEncoding
internal Encoding QueryStringEncoding {get{Encoding contentEncoding = this.ContentEncoding;if (!contentEncoding.Equals(Encoding.Unicode)){return contentEncoding;}return Encoding.UTF8;} } //點(diǎn)擊進(jìn)入this.ContentEncoding則為: public Encoding ContentEncoding {get{if (!this._flags[0x20] || (this._encoding == null)){this._encoding = this.GetEncodingFromHeaders();if (this._encoding == null){GlobalizationSection globalization = RuntimeConfig.GetLKGConfig(this._context).Globalization;this._encoding = globalization.RequestEncoding;}this._flags.Set(0x20);}return this._encoding;}set{this._encoding = value;this._flags.Set(0x20);} }
說明:
從QueryStringEncoding代碼得出,系統(tǒng)默認(rèn)會(huì)先取globalization配置節(jié)點(diǎn)的編碼方式,如果取不到,則默認(rèn)為UTF-8編碼方式2.4:切入 ?FillFromString(string?s,?bool?urlencoded,?Encoding?encoding)
?
Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/-->internal void FillFromString(string s, bool urlencoded, Encoding encoding) {int num = (s != null) ? s.Length : 0;for (int i = 0; i < num; i++){int startIndex = i;int num4 = -1;while (i < num){char ch = s[i];if (ch == '='){if (num4 < 0){num4 = i;}}else if (ch == '&'){break;}i++;}string str = null;string str2 = null;if (num4 >= 0){str = s.Substring(startIndex, num4 - startIndex);str2 = s.Substring(num4 + 1, (i - num4) - 1);}else{str2 = s.Substring(startIndex, i - startIndex);}if (urlencoded)//外面的傳值默認(rèn)是true,所以會(huì)執(zhí)行以下語句{base.Add(HttpUtility.UrlDecode(str, encoding), HttpUtility.UrlDecode(str2, encoding));}else{base.Add(str, str2);}if ((i == (num - 1)) && (s[i] == '&')){base.Add(null, string.Empty);}} }
說明:
從這點(diǎn)我們發(fā)現(xiàn):所有的參數(shù)輸入,都調(diào)用了一次:HttpUtility.UrlDecode(str2,?encoding);3:結(jié)論出來了
當(dāng)客戶端js對(duì)中文以u(píng)tf-8編碼提交到服務(wù)端時(shí),用Request.QueryString接收時(shí),會(huì)先以globalization配置的gb2312去解碼一次,于是,產(chǎn)生了亂碼。所有的起因?yàn)?#xff1a;
1:js編碼方式為urt-82:服務(wù)端又配置了默認(rèn)為gb2312
3:Request.QueryString默認(rèn)又會(huì)調(diào)用HttpUtility.UrlDecode用系統(tǒng)配置編碼去解碼接收參數(shù)。
?
文章補(bǔ)充:
1:系統(tǒng)取默認(rèn)編碼的順序?yàn)?#xff1a;http請求頭->globalization配置節(jié)點(diǎn)-》默認(rèn)UTF-82:在Url直接輸入中文時(shí),不同瀏覽器處理方式可能不同如:ie不進(jìn)行編碼直接提交,firefox對(duì)url進(jìn)行g(shù)b2312編碼后提交。
3:對(duì)于未編碼“中文字符”,使用Request.QueryString時(shí)內(nèi)部調(diào)用HttpUtility.UrlDecode后,由gb2312->utf-8時(shí),
如果查不到該中文字符,默認(rèn)轉(zhuǎn)成"%ufffd",因此出現(xiàn)不可逆亂碼。
?
?
4:解決之路
知道了原理,解決的方式也有多種多樣了:
1:全局統(tǒng)一為UTF-8編碼,省事又省心。
?
2:全局指定了GB2312編碼時(shí),url帶中文,js非編碼不可,如ext.js框架。
這種方式你只能特殊處理,在服務(wù)端指定編碼解碼,因?yàn)槟J(rèn)系統(tǒng)調(diào)用了一次HttpUtility.UrlDecode("xxx",系統(tǒng)配置的編碼),
因此你再調(diào)用一次HttpUtility.UrlEncode("xxx",系統(tǒng)配置的編碼),返回到原始urt-8編碼參數(shù)
再用HttpUtility.UrlDecode("xxx",utf-8),解碼即可。
?
5:其它說明:默認(rèn)對(duì)進(jìn)行一次解碼的還包括URI屬性,而Request.RawUrl則為原始參數(shù)
http://www.cnblogs.com/cyq1162/archive/2010/11/29/1891124.html
總結(jié)
以上是生活随笔為你收集整理的Request 接收参数乱码原理解析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android第十期 - 百度地图
- 下一篇: Flex中的图表