I morse fick jag en fråga av en kollega: Jag sa att de mottagna parametrarna var förvrängda, låt mig hjälpa till att lösa det.
Plattformen som min kollega ansvarar för är byggd Ext.js ramverk, och konfigurationsfilen web.config är konfigurerad med den globala "GB2312"-kodningen:
<globalization requestEncoding="gb2312" responseEncoding="gb2312" fileEncoding="gb2312" culture="zh-CN"/>
När frontend skickar in "kinesisk text" får backend förvrängda tecken med Request.QueryString["xxx"].
Oavsett hur du avkodar med System.Web.HttpUtility.UrlDecode("xxx", "encoding type") fungerar det inte.
Huvudbeskrivning: 1: Det första att avgöra är att när klientens URL-parametrar skickas in, kommer Ext.js att koda dem innan de skickas in, och klientens kodning är UTF-8-kodning som standard
2: Varför är det då förvrängt när man tar emot parametrar med Request.QueryString["xxx"]?
Vi vänder på kompileringen steg för steg, 2.1: Titta på koden för egenskapen 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;
- }
- }
Kopiera koden
2.2: Skär in i FillInQueryStringCollection()-metoden
- 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);
-
- }
- }
Kopiera koden
2.3: Klipp: 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);
- }
- }
Kopiera kodenFrån QueryStringEncoding-koden går systemet tillbaka till kodningsmetoden för globaliseringskonfigurationsnoden, och om inte, är standarden UTF-8-kodning 2.4: Skär i FillFromString (sträng s, bool urlencoded, kodningskodning)
- 代码有点长,就折叠起来了
- 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);
- }
- }
- }
Kopiera kodenFrån denna punkt finner vi att alla parameterindata anropas en gång: HttpUtility.UrlDecode(str2, kodning);
När klient js skickar in kinesiska till servern i utf-8-kodning, kommer den först att avkoda den med Request.QueryString när den tas emot med gb2312 konfigurerad av globalisering, vilket resulterar i förvrängda tecken.
1: JS-kodningsmetoden är URT-8
2: Serversidan har konfigurerat standardinställningen till GB2312
3: Request.QueryString anropar HttpUtility.UrlDecode som standard för att avkoda de mottagna parametrarna med systemkonfigurationskodning.
1: Systemet väljer standardkodningen i följande ordning: http-begäran-header - >globaliseringskonfigurationsnod - standard UTF-8
2: När URL:en matas in direkt till kinesiska kan olika webbläsare hantera det olika, till exempel: IE kodar inte och skickar in direkt, Firefox skickar in URL:en efter GB2312-kodningen.
3: För okodade "kinesiska tecken", efter att ha använt Request.QueryString internt anrop HttpUtility.UrlDecode, av gb2312->utf-8,
Om det kinesiska tecknet inte hittas kommer det att konverteras till "%ufffd" som standard, vilket resulterar i irreversibla förvrängda tecken.
4: Vägen till lösning Med tanke på principen finns det många sätt att lösa den: 1: Den globala föreningen är UTF-8-kodning, vilket sparar besvär och oro.
2: När GB2312 är globalt specificerad är url:en kinesisk och js måste kodas, till exempel ext.js ramverk.
På så sätt kan du bara hantera det speciellt, genom att specificera kodning och avkodning på serversidan. Eftersom standardsystemet anropar HttpUtility.UrlDecode("xxx", kodningen av systemkonfigurationen) en gång, Så du anropar HttpUtility.UrlEncode("xxx", kodningen konfigurerad av systemet) igen för att återgå till den ursprungliga urt-8-kodningsparametern
Använd sedan HttpUtility.UrlDecode("xxx", utf-8) för att avkoda den. sträng AAA = begäran. Request.QueryString["admin"]; Husägare sträng a1 = HttpUtility.UrlEncode(aaa, System.Text.Encoding.GetEncoding("GB2312")); sträng a2 = HttpUtility.UrlDecode(a1,System.Text.Encoding.UTF8);
|