În această dimineață am primit o întrebare de la un coleg: am spus că parametrii primiți sunt distorsionați, lasă-mă să ajut la rezolvarea problemei.
Platforma de care este responsabil colegul meu este construită Ext.js framework, iar fișierul de configurare web.config este configurat cu codificarea globală "GB2312":
<globalization requestEncoding="gb2312" responseEncoding="gb2312" fileEncoding="gb2312" culture="zh-CN"/>
Când frontend-ul trimite "textul chinezesc", backend-ul primește caractere distorsionate cu Request.QueryString["xxx"].
Indiferent cum decodezi cu System.Web.HttpUtility.UrlDecode("xxx", "encoding type"), nu funcționează.
Descrierea principiului: 1: Primul lucru de stabilit este că atunci când parametrii URL ai clientului sunt trimiși, Ext.js îi va codifica înainte de a-i trimite, iar codarea clientului este implicită UTF-8
2: Atunci de ce este distorsionat când primești parametri cu Request.QueryString["xxx"]?
Inversăm compilația pas cu pas, 2.1: Uită-te la codul proprietății 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();//重点代码切入点
- }
- this._queryString.MakeReadOnly();
- }
- if (this._flags[1])
- {
- this._flags.Clear(1);
- ValidateNameValueCollection(this._queryString, "Request.QueryString");
- }
- return this._queryString;
- }
- }
Cod de copiere
2.2: Decupare în metoda FillInQueryStringCollection()
- Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/-->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);
-
- }
- }
Cod de copiere
2.3: Cut: QueryStringEncoding
- Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/-->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);
- }
- }
Cod de copiereDin codul QueryStringEncoding, sistemul folosește implicit metoda de codare a nodului de configurare a globalizării, iar dacă nu, implicit este codarea UTF-8 2.4: Tăie în FillFromString(string s, bool urlencoded, codare 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)//外面的传值默认是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);
- }
- }
- }
Cod de copiereDin acest punct constatăm că toate intrările parametrilor sunt numite o singură dată: HttpUtility.UrlDecode(str2, codificare);
Când clientul js trimite chineză serverului prin codare utf-8, când îl primește cu Request.QueryString, îl va decoda mai întâi o dată cu gb2312 configurat prin globalizare, rezultând caractere distorsionate.
1: Metoda de codare JS este URT-8
2: Partea serverului a configurat implicit GB2312
3: Request.QueryString va apela implicit HttpUtility.UrlDecode pentru a decoda parametrii primiți prin codificarea configurării sistemului.
1: Sistemul selectează codificarea implicită în următoarea ordine: antet de cerere http - >nod de configurare globalizare - implicit UTF-8
2: Când introduci URL-ul direct în chineză, diferite browsere pot gestiona diferit, de exemplu: IE nu codifică și trimite direct, Firefox trimite URL-ul după codificarea GB2312.
3: Pentru "caractere chinezești" necodificate, după folosirea apelului intern Request.QueryString HttpUtility.UrlDecode, de gb2312->utf-8,
Dacă caracterul chinezesc nu este găsit, acesta va fi convertit implicit în "%ufffd", rezultând caractere ireversibile și distorsionate.
4: Drumul spre rezolvare Cunoscând principiul, există multe moduri de a o rezolva: 1: Unificarea globală este codificarea UTF-8, care economisește probleme și griji.
2: Când GB2312 este specificat global, URL-ul este chinezesc, iar js trebuie codificat, cum ar fi ext.js framework.
Astfel, poți gestiona doar în mod special, specificând codarea și decodarea pe partea de server. Pentru că sistemul implicit apelează HttpUtility.UrlDecode("xxx", codificarea configurației sistemului) o dată, Așadar, apelezi din nou la HttpUtility.UrlEncode("xxx", codarea configurată de sistem) pentru a reveni la parametrul original de codare urt-8
Apoi folosește HttpUtility.UrlDecode("xxx", utf-8) pentru a-l decoda. Șirul AAA = Cerere. Request.QueryString["admin"]; Proprietar string a1 = HttpUtility.UrlEncode(aaa, System.Text.Encoding.GetEncoding("GB2312")); șirul a2 = HttpUtility.UrlDecode(a1,System.Text.Encoding.UTF8);
|