Request 接收引數亂碼原理解析
今天早上被同事問了一個問題:說接收到的引數是亂碼,讓我幫著解決一下。
實際情景:
同事負責的平臺是Ext.js框架搭建的,web.config配置檔案裡配置了全域性為“GB2312”編碼:
當前臺提交“中文文字”時,後臺用Request.QueryString["xxx"]接收到的是亂碼。
無論用System.Web.HttpUtility.UrlDecode("xxx","編碼型別")怎麼解碼都無效。
原理說明:
1:首先確定的是:客戶端的url引數在提交時,Ext.js會對其編碼再提交,而客戶端的編碼預設是utf-8編碼
客戶端預設有三種編碼函式:escape() encodeURI() encodeURIComponent()
2:那為什麼用Request.QueryString["xxx"]接收引數時,收到的會是亂碼?
為此,我們必須解開Request.QueryString的原始處理邏輯過程
我們步步反編繹,
2.1:看QueryString屬性的程式碼:
public NameValueCollection QueryString { get { if (this._queryString == null) { this._queryString = new HttpValueCollection(); if (this._wr != null) { this.FillInQueryStringCollection();//重點程式碼切入點 } 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); } }//上面是對流位元組的處理,即檔案上傳之類的。 else if (!string.IsNullOrEmpty(this.QueryStringText)) { //下面這句是對普通檔案提交的處理:FillFromString是個切入點,編碼切入點是:this.QueryStringEncoding this._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; } } //點選進入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程式碼得出,系統預設會先取globalization配置節點的編碼方式,如果取不到,則預設為UTF-8編碼方式
2.4:切入 FillFromString(string s, bool urlencoded, Encoding encoding)
internal void FillFromString(string s, bool urlencoded, Encoding encoding) { int num = (s != null) ? s.Length : 0; for (int i = 0; i = 0) { str = s.Substring(startIndex, num4 - startIndex); str2 = s.Substring(num4 + 1, (i - num4) - 1); } else { str2 = s.Substring(startIndex, i - startIndex); } if (urlencoded)//外面的傳值預設是true,所以會執行以下語句 { 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); } } }
說明:
從這點我們發現:所有的引數輸入,都呼叫了一次:HttpUtility.UrlDecode(str2, encoding);
3:結論出來了
當客戶端js對中文以utf-8編碼提交到服務端時,用Request.QueryString接收時,會先以globalization配置的gb2312去解碼一次,於是,產生了亂碼。
所有的起因為:
1:js編碼方式為urt-8
2:服務端又配置了預設為gb2312
3:Request.QueryString預設又會呼叫HttpUtility.UrlDecode用系統配置編碼去解碼接收引數。
補充:
1:系統取預設編碼的順序為:http請求頭->globalization配置節點-》預設UTF-8
2:在Url直接輸入中文時,不同瀏覽器處理方式可能不同如:ie不進行編碼直接提交,firefox對url進行gb2312編碼後提交。
3:對於未編碼“中文字元”,使用Request.QueryString時內部呼叫HttpUtility.UrlDecode後,由gb2312->utf-8時,
如果查不到該中文字元,預設轉成"%ufffd",因此出現不可逆亂碼。
4:解決之路
知道了原理,解決的方式也有多種多樣了:
1:全域性統一為UTF-8編碼,省事又省心。
2:全域性指定了GB2312編碼時,url帶中文,js非編碼不可,如ext.js框架。
這種方式你只能特殊處理,在服務端指定編碼解碼,
因為預設系統呼叫了一次HttpUtility.UrlDecode("xxx",系統配置的編碼),
因此你再呼叫一次HttpUtility.UrlEncode("xxx",系統配置的編碼),返回到原始urt-8編碼引數
再用HttpUtility.UrlDecode("xxx",utf-8),解碼即可。
5:其它說明:預設對進行一次解碼的還包括URI屬性,而Request.RawUrl則為原始引數
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/1916/viewspace-2800988/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- PHP接收GET中文引數亂碼深入研究PHP
- request的get和post引數亂碼問題
- JavaWeb基礎-Request物件接收表單請求引數JavaWeb物件
- Servlet接收JSP引數亂碼問題解決辦法薦ServletJS
- Jsp/Servlet接收FORM表格引數時輸出亂碼的處理 (轉)JSServletORM
- SpringMVC原始碼之引數解析繫結原理SpringMVC原始碼
- MyBatis 如何接收引數MyBatis
- Ajax接收int型別亂碼型別
- nodejs接收get引數和post引數NodeJS
- request/response解決中文亂碼
- jQuery接收url的引數jQuery
- Go 接收命令列引數Go命令列
- Laravel request 獲取路由引數Laravel路由
- Charles 修改請求(Request)引數
- Oracle引數檔案解析——引數解析Oracle
- java Socket接收資料亂碼問題Java
- Go函式接收可變引數Go函式
- GET請求引數為中文時亂碼分析
- 解決Url帶中文引數亂碼問題
- pytest-引數request的使用
- 給一個介面傳遞引數,並接收返回的引數
- java中解決request中文亂碼問題Java
- js解決url傳引數中文亂碼問題JS
- Laravel同時接收路由引數和查詢字串中的引數Laravel路由字串
- [ASP.NET] 使用Request 傳遞引數ASP.NET
- request的請求引數獲取方式
- 獲取request中的查詢引數
- Shell解析引數
- javascript獲取url引數值出現亂碼解決JavaScript
- Laravel 修改器能加Request引數嗎?Laravel
- JDBC亂碼引發的"血案"JDBC
- Android 頁面跳轉傳遞引數及頁面返回接收引數Android
- CNN模型引數解析CNN模型
- js解析url引數JS
- canvas transform引數解析CanvasORM
- 解析型別引數型別
- ThreadPoolExecutor 引數解析thread
- ogg引數解析