이 글은 기계 번역의 미러 문서이며, 원본 기사로 바로 이동하려면 여기를 클릭해 주세요.

보기: 23136|회답: 0

[출처] c# 요청은 매개변수에 대해 뒤섞인 문자를 받습니다

[링크 복사]
게시됨 2015. 12. 25. 오후 6: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", "encoding type")로 어떻게 디코딩해도 작동하지 않습니다.

원리 설명:
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 코드에서 시스템은 globalization 구성 노드의 인코딩 방식을 기본값으로 사용하며, 그렇지 않으면 기본값은 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, 인코딩);

클라이언트 js가 utf-8 인코딩으로 서버에 중국어를 제출할 때, Request.QueryString으로 받으면 먼저 gb2312로 한 번 디코딩되어 글자가 뒤섞여 나타납니다.

1: JS 인코딩 방법은 URT-8입니다

2: 서버 측에서 기본값을 GB2312로 설정했습니다

3: Request.QueryString은 기본적으로 HttpUtility.UrlDecode를 호출하여 시스템 구성 인코딩으로 받은 매개변수를 디코딩합니다.

1: 시스템이 기본 인코딩을 다음 순서로 선택합니다: http request header - >globalization configuration node - default 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"));
                            문자열 a2 = HttpUtility.UrlDecode(a1,System.Text.Encoding.UTF8);








이전의:안녕
다음:정말 복잡한 알고리즘이에요, 며칠째 우울했어요.
면책 조항:
Code Farmer Network에서 발행하는 모든 소프트웨어, 프로그래밍 자료 또는 기사는 학습 및 연구 목적으로만 사용됩니다; 위 내용은 상업적 또는 불법적인 목적으로 사용되지 않으며, 그렇지 않으면 모든 책임이 사용자에게 부담됩니다. 이 사이트의 정보는 인터넷에서 가져온 것이며, 저작권 분쟁은 이 사이트와는 관련이 없습니다. 위 내용은 다운로드 후 24시간 이내에 컴퓨터에서 완전히 삭제해야 합니다. 프로그램이 마음에 드신다면, 진짜 소프트웨어를 지원하고, 등록을 구매하며, 더 나은 진짜 서비스를 받아주세요. 침해가 있을 경우 이메일로 연락해 주시기 바랍니다.

Mail To:help@itsvse.com