Сьогодні вранці колега поставив мені запитання: я сказав, що отримані параметри були спотворені, дозвольте мені допомогти це розв'язати.
Платформа, за яку відповідає мій колега, побудована 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:
- 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, кодування кодування)
- 代码有点长,就折叠起来了
- 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, кодування);
Коли клієнт 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 надсилає URL після кодування GB2312.
3: Для незакодованих «китайських ієрогліфів» після використання внутрішнього виклику Request.QueryString HttpUtility.UrlDecode, за допомогою gb2312->utf-8,
Якщо китайський ієрогліф не знайдено, він за замовчуванням конвертується у «%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);
|