この記事は機械翻訳のミラー記事です。元の記事にジャンプするにはこちらをクリックしてください。

眺める: 23136|答える: 0

[出典] c# リクエストはパラメータに対して乱れた文字を受け取る

[リンクをコピー]
掲載地 2015/12/25 18:41:49 | | | |


今朝、同僚から質問されました。私は「受け取ったパラメータが混乱しているので、解決を手伝わせてください」と答えました。


同僚が担当しているプラットフォームはフレームワーク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プロパティのコードをご覧ください:

  1. Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/-->public NameValueCollection QueryString
  2. {
  3.     get
  4.     {
  5.         if (this._queryString == null)
  6.         {
  7.             this._queryString = new HttpValueCollection();
  8.             if (this._wr != null)
  9.             {
  10.                 this.FillInQueryStringCollection();//重点代码切入点
  11.             }
  12.             this._queryString.MakeReadOnly();
  13.         }
  14.         if (this._flags[1])
  15.         {
  16.             this._flags.Clear(1);
  17.             ValidateNameValueCollection(this._queryString, "Request.QueryString");
  18.         }
  19.         return this._queryString;
  20.     }
  21. }
コードをコピーします

2.2: FillInQueryStringCollection() メソッドに切り込む

  1. Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/-->private void FillInQueryStringCollection()
  2. {
  3.     byte[] queryStringBytes = this.QueryStringBytes;
  4.     if (queryStringBytes != null)
  5.     {
  6.         if (queryStringBytes.Length != 0)
  7.         {
  8.             this._queryString.FillFromEncodedBytes(queryStringBytes, this.QueryStringEncoding);
  9.         }
  10.     }//上面是对流字节的处理,即文件上传之类的。
  11.     else if (!string.IsNullOrEmpty(this.QueryStringText))
  12.     {
  13.         //下面这句是对普通文件提交的处理:FillFromString是个切入点,编码切入点是:this.QueryStringEncoding
  14.         this._queryString.FillFromString(this.QueryStringText, true, this.QueryStringEncoding);
  15.         
  16.     }
  17. }
コードをコピーします

2.3: カット:QueryStringEncoding

  1. Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/-->internal Encoding QueryStringEncoding
  2. {
  3.     get
  4.     {
  5.         Encoding contentEncoding = this.ContentEncoding;
  6.         if (!contentEncoding.Equals(Encoding.Unicode))
  7.         {
  8.             return contentEncoding;
  9.         }
  10.         return Encoding.UTF8;
  11.     }
  12. }
  13. //点击进入this.ContentEncoding则为:
  14. public Encoding ContentEncoding
  15. {
  16.     get
  17.     {
  18.         if (!this._flags[0x20] || (this._encoding == null))
  19.         {
  20.             this._encoding = this.GetEncodingFromHeaders();
  21.             if (this._encoding == null)
  22.             {
  23.                 GlobalizationSection globalization = RuntimeConfig.GetLKGConfig(this._context).Globalization;
  24.                 this._encoding = globalization.RequestEncoding;
  25.             }
  26.             this._flags.Set(0x20);
  27.         }
  28.         return this._encoding;
  29.     }
  30.     set
  31.     {
  32.         this._encoding = value;
  33.         this._flags.Set(0x20);
  34.     }
  35. }
コードをコピーします
QueryStringEncodingコードからは、システムはグローバル化構成ノードのエンコーディング方式をデフォルトで使用し、そうでない場合はデフォルトでUTF-8エンコーディングとなります
2.4: FillFromString(文字列s、bool urlencoded、Encoding encoding)にカット

  1. 代码有点长,就折叠起来了

  2. Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/-->internal void FillFromString(string s, bool urlencoded, Encoding encoding)
  3. {
  4.     int num = (s != null) ? s.Length : 0;
  5.     for (int i = 0; i < num; i++)
  6.     {
  7.         int startIndex = i;
  8.         int num4 = -1;
  9.         while (i < num)
  10.         {
  11.             char ch = s[i];
  12.             if (ch == '=')
  13.             {
  14.                 if (num4 < 0)
  15.                 {
  16.                     num4 = i;
  17.                 }
  18.             }
  19.             else if (ch == '&')
  20.             {
  21.                 break;
  22.             }
  23.             i++;
  24.         }
  25.         string str = null;
  26.         string str2 = null;
  27.         if (num4 >= 0)
  28.         {
  29.             str = s.Substring(startIndex, num4 - startIndex);
  30.             str2 = s.Substring(num4 + 1, (i - num4) - 1);
  31.         }
  32.         else
  33.         {
  34.             str2 = s.Substring(startIndex, i - startIndex);
  35.         }
  36.         if (urlencoded)//外面的传值默认是true,所以会执行以下语句
  37.         {
  38.             base.Add(HttpUtility.UrlDecode(str, encoding), HttpUtility.UrlDecode(str2, encoding));
  39.         }
  40.         else
  41.         {
  42.             base.Add(str, str2);
  43.         }
  44.         if ((i == (num - 1)) && (s[i] == '&'))
  45.         {
  46.             base.Add(null, string.Empty);
  47.         }
  48.     }
  49. }
コードをコピーします
ここからすべてのパラメータ入力は一度だけ呼び出されます: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);








先の:こんにちは
次に:なんてアルゴリズムでしょう。数日間落ち込んでいました。
免責事項:
Code Farmer Networkが発行するすべてのソフトウェア、プログラミング資料、記事は学習および研究目的のみを目的としています。 上記の内容は商業的または違法な目的で使用されてはならず、そうでなければ利用者はすべての結果を負うことになります。 このサイトの情報はインターネットからのものであり、著作権紛争はこのサイトとは関係ありません。 ダウンロード後24時間以内に上記の内容を完全にパソコンから削除してください。 もしこのプログラムを気に入ったら、正規のソフトウェアを支持し、登録を購入し、より良い本物のサービスを受けてください。 もし侵害があれば、メールでご連絡ください。

Mail To:help@itsvse.com