Esta manhã, um colega me fez uma pergunta: eu disse que os parâmetros recebidos estavam distorcidos, deixe-me ajudar a resolver.
A plataforma pela qual meu colega é responsável é construída Ext.js framework, e o arquivo de configuração web.config está configurado com a codificação global "GB2312":
<globalization requestEncoding="gb2312" responseEncoding="gb2312" fileEncoding="gb2312" culture="zh-CN"/>
Quando o frontend envia o "texto chinês", o backend recebe caracteres distorcidos com Request.QueryString["xxx"].
Não importa como você decodifica com System.Web.HttpUtility.UrlDecode("xxx", "tipo de codificação"), isso não funciona.
Descrição do princípio: 1: A primeira coisa a determinar é que, quando os parâmetros da URL do cliente são enviados, Ext.js os codificará antes de enviá-los, e a codificação do cliente é codificação UTF-8 por padrão
2: Então por que está distorcido ao receber parâmetros com Request.QueryString["xxx"]?
Invertemos a compilação passo a passo, 2.1: Veja o código da propriedade 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;
- }
- }
Copiar código
2.2: Corte no método 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);
-
- }
- }
Copiar código
2.3: Corte: 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);
- }
- }
Copiar códigoA partir do código QueryStringEncoding, o sistema adota por padrão o método de codificação do nó de configuração de globalização e, se não o fizer, o padrão é a codificação UTF-8 2.4: Cortar em FillFromString (string s, bool urlencoded, codificação de codificação)
- 代码有点长,就折叠起来了
- 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);
- }
- }
- }
Copiar códigoA partir desse ponto, descobrimos que todas as entradas de parâmetros são chamadas uma vez: HttpUtility.UrlDecode(str2, codificação);
Quando o js cliente envia chinês ao servidor na codificação utf-8, ao recebê-lo com Request.QueryString, ele primeiro o decodifica uma vez com gb2312 configurado pela globalização, resultando em caracteres distorcidos.
1: O método de codificação JS é URT-8
2: O lado do servidor configurou o padrão para GB2312
3: Request.QueryString chamará HttpUtility.UrlDecode por padrão para decodificar os parâmetros recebidos com codificação de configuração do sistema.
1: O sistema seleciona a codificação padrão na seguinte ordem: cabeçalho de requisição http - nó de configuração >globalização - UTF-8 padrão
2: Ao inserir a URL diretamente no chinês, diferentes navegadores podem lidar com isso de formas distintas, por exemplo: IE não codifica e envia diretamente, o Firefox envia a URL após a codificação GB2312.
3: Para "caracteres chineses" não codificados, após usar a chamada interna Request.QueryString HttpUtility.UrlDecode, por gb2312->utf-8,
Se o caractere chinês não for encontrado, ele será convertido por padrão em "%ufffd", resultando em caracteres distorcidos irreversíveis.
4: O caminho para a resolução Conhecendo o princípio, existem muitas maneiras de resolvê-lo: 1: A unificação global é a codificação UTF-8, que evita problemas e preocupações.
2: Quando GB2312 é especificado globalmente, a URL é chinesa, e o js deve ser codificado, como ext.js framework.
Dessa forma, você só pode lidar com isso de forma especial, especificando a codificação e decodificação no lado do servidor. Como o sistema padrão chama HttpUtility.UrlDecode("xxx", a codificação da configuração do sistema) uma vez, Então você chama HttpUtility.UrlEncode ("xxx", a codificação configurada pelo sistema) novamente para retornar ao parâmetro original de codificação urt-8
Depois, use HttpUtility.UrlDecode("xxx", utf-8) para decodificar. string AAA = Solicitação. Request.QueryString["admin"]; Proprietário string a1 = HttpUtility.UrlEncode(aaa, System.Text.Encoding.GetEncoding("GB2312")); string a2 = HttpUtility.UrlDecode(a1,System.Text.Encoding.UTF8);
|