今朝、同僚から質問されました。私は「受け取ったパラメータが混乱しているので、解決を手伝わせてください」と答えました。
同僚が担当しているプラットフォームはフレームワークExt.js構築されており、web.configの設定ファイルはグローバルな「GB2312」エンコーディングで設定されています。
<globalization requestEncoding="gb2312" responseEncoding="gb2312" fileEncoding="gb2312" culture="zh-CN"/>
フロントエンドが「中国語テキスト」を送信すると、バックエンドはRequest.QueryString["xxx"]で乱れた文字を受け取ります。
System.Web.HttpUtility.UrlDecode("xxx"、「エンコーディングタイプ」)でどのようにデコードしても、動作しません。
原理説明: 1: まず確認すべきは、クライアントのURLパラメータが提出された際に、Ext.jsがそれを提出前にエンコードし、クライアントのエンコーディングがデフォルトでUTF-8エンコーディングであることです
2: では、なぜRequest.QueryString["xxx"]でパラメータを受け取ると混乱するのですか?
コンパイルを段階的に逆にしてみます。 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();//重点代码切入点
- }
- this._queryString.MakeReadOnly();
- }
- if (this._flags[1])
- {
- this._flags.Clear(1);
- ValidateNameValueCollection(this._queryString, "Request.QueryString");
- }
- return this._queryString;
- }
- }
コードをコピーします
2.2: 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);
-
- }
- }
コードをコピーします
2.3: カット: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);
- }
- }
コードをコピーしますQueryStringEncodingコードからは、システムはグローバル化構成ノードのエンコーディング方式をデフォルトで使用し、そうでない場合はデフォルトでUTF-8エンコーディングとなります 2.4: FillFromString(文字列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)//外面的传值默认是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);
クライアントjsがutf-8エンコーディングでサーバーに中国語を送信し、Request.QueryStringで受信すると、まずグローバリゼーションで設定されたgb2312で一度デコードされ、文字が乱れます。
1: JSの符号化方法はURT-8です
2: サーバー側がデフォルトをGB2312に設定しています
3: Request.QueryStringはデフォルトでHttpUtility.UrlDecodeを呼び出し、システム構成エンコーディングで受信パラメータをデコードします。
1: システムはデフォルトのエンコーディングを次の順序で選択します: httpリクエストヘッダー - >グローバライゼーション設定ノード - デフォルトUTF-8
2: URLを直接中国語に入力する場合、ブラウザによって処理が異なる場合があります。例えば、IEはエンコードせずに直接送信しますが、FirefoxはGB2312エンコーディング後にURLを送信します。
3: 未エンコードの「中国語」に対して、gb2312->utf-8によるRequest.QueryString内部呼び出しHttpUtility.UrlDecodeを使用した後、
中国語の漢字が見つからない場合、デフォルトで「%ufffd」に変換され、元に戻らない乱れ文字になります。
4:解決への道 この原理を知っていると、解く方法はたくさんあります。 1: グローバル統合はUTF-8エンコーディングで、手間や心配を省きます。
2: GB2312がグローバルに指定されている場合、URLは中国語で、jsはext.jsフレームワークのようにエンコードする必要があります。
このようにして、エンコードとデコードはサーバー側で指定する特別な処理しかできません。 デフォルトシステムはHttpUtility.UrlDecode("xxx"、システム構成のエンコーディング)を一度だけ呼び出しているため、 そこで、システムが設定したHttpUtility.UrlEncode("xxx")を再度呼び出して、元のurt-8エンコーディングパラメータに戻します
次にHttpUtility.UrlDecode("xxx", utf-8)を使ってデコードします。 文字列 aaa = リクエスト。 Request.QueryString["admin"]; 住宅所有者 string a1 = HttpUtility.UrlEncode(aaa, System.Text.Encoding.GetEncoding("GB2312")); string a2 = HttpUtility.UrlDecode(a1,System.Text.Encoding.UTF8);
|