Какая разница между Request.Url.Query и Request.QueryString?
Я отслеживаю ошибку в приложении Url Rewriting. Ошибка возникла как проблема кодирования некоторых диакритических символов в запросе.
В основном проблема заключалась в том, что запрос, который был в основном /search.aspx?search=heřmánek, переписывался с помощью запроса "search = he% c5% 99m% c3% a1nek"
Правильное значение (с использованием какого-то другого рабочего кода) было перепиской запроса: "search = he% u0159m% u00e1nek"
Обратите внимание на разницу между двумя строками. Однако, если вы опубликуете оба, вы увидите, что кодировка Url воспроизводит одну и ту же строку. Это не до тех пор, пока вы не используете контекст. Перепишите функцию, которая прерывается кодировкой. Сломанная строка возвращает "heÅmánek" (используя Request.QueryString [ "Поиск" ], а рабочая строка возвращает "heřmánek". Это изменение происходит после вызова функции перезаписи.
Я проследил это до одного набора кода, используя Request.QueryString(рабочий), а другой с помощью Request.Url.Query(request.Url возвращает экземпляр Uri).
Пока я выработал ошибку, в моем понимании есть дыра, поэтому, если кто-то знает разницу, я готов к уроку.
Ответы
Ответ 1
То, что вы указали как "сломанную" кодированную строку, на самом деле является правильной кодировкой в соответствии со стандартами. Тот, который вы указали как "правильное" кодирование, использует нестандартное расширение для спецификаций, чтобы разрешить формат %uXXXX
(я считаю, что он должен указывать кодировку UTF-16).
В любом случае "сломанная" кодированная строка в порядке. Вы можете использовать следующий код, чтобы проверить, что:
Uri uri = new Uri("http://www.example.com/test.aspx?search=heřmánek");
Console.WriteLine(uri.Query);
Console.WriteLine(HttpUtility.UrlDecode(uri.Query));
Прекрасно работает. Однако... по подозрению, я попробовал UrlDecode с указанной кодировкой Latin-1 вместо UTF-8 по умолчанию:
Console.WriteLine(HttpUtility.UrlDecode(uri.Query,
Encoding.GetEncoding("iso-8859-1")));
... и я получил плохое значение, которое вы указали, "heÅmánek". Другими словами, похоже, что вызов HttpContext.RewritePath()
каким-то образом изменяет urlencoding/decoding, чтобы использовать кодировку Latin-1, а не UTF-8, которая является кодировкой по умолчанию, используемой методами UrlEncode/Decode.
Это похоже на ошибку, если вы спросите меня. Вы можете посмотреть код RewritePath()
в рефлекторе и увидеть, что он определенно играет с querystring - передавая его всем видам функций виртуального пути и к некоторому неуправляемому коду IIS.
Интересно, где-то по пути, Uri в ядре объекта Request обрабатывается с неправильной кодовой страницей? Это объясняет, почему Request.Querystring
(который является просто исходными значениями из заголовков HTTP) будет правильным, тогда как Uri, использующий неправильную кодировку для диакритических знаков, будет неправильным.
Ответ 2
Ваш вопрос действительно вызвал мой интерес, поэтому я проделал некоторое чтение за последний час или около того. Я не совсем уверен, что нашел ответ, но я выброшу его, чтобы посмотреть, что вы думаете.
Из того, что я читал до сих пор, Request.QueryString на самом деле является "анализируемой версией переменной QUERY_STRING в коллекции ServerVariables" [reference], где в качестве Request.Url(как вы сказали) необработанный URL, инкапсулированный в объект Uri. Согласно в этой статье, конструктор класса Uri... анализирует строку [url string], помещает ее в каноническом формате и делает любые требуемые escape-коды ".
Следовательно, похоже, что Request.QueryString использует другую функцию для анализа переменной QUERY_STRING из конструктора ServerVariables. Это объясняет, почему вы видите разницу между ними. Теперь почему различные методы кодирования используются специальной функцией синтаксического анализа, а функция разбора объектов Uri полностью вне меня. Может быть, кто-то более разбирается в DLL aspnet_isapi, может дать некоторые ответы на этот вопрос.
В любом случае, надеюсь, мой пост имеет смысл. На стороне примечания, я хотел бы добавить еще одну ссылку, которая также содержит некоторые очень подробные и интересные показания: http://download.microsoft.com/download/6/c/a/6ca715c5-2095-4eec-a56f-a5ee904a1387/Ch-12_HTTP_Request_Context.pdf
Ответ 3
Я провел несколько исследований за последний день или около того, и я думаю, что у меня есть информация об этом.
Когда вы используете Request.Querystring или HttpUtility.UrlDecode(или Encode), он использует кодировку, указанную в элементе (в частности, атрибут requestEncoding) web.config(или иерархию .config, если у вас нет ) --- НЕ Encoding.Default, которая является кодировкой по умолчанию для вашего сервера.
Когда у вас установлена кодировка UTF-8, один символ Юникода может быть закодирован как 2% xx шестнадцатеричных значений. Он также будет декодирован таким образом, когда будет задано целое значение.
Если вы являетесь UrlDecoding с другим кодированием, чем был закодирован url, вы получите другой результат.
Так как HttpUtility.UrlEncode и UrlDecode могут принимать параметр кодирования, его соблазн попытаться кодировать с использованием кодовой страницы ANSI, но UTF-8 - это правильный путь, если у вас есть поддержка браузера (по-видимому, старые версии не поддерживают UTF-8). Вам просто нужно убедиться, что он правильно установлен, и обе стороны будут работать нормально.
UTF-8 Кажется, это кодировка по умолчанию: (из .net-отражателя System.Web.HttpRequest)
internal Encoding QueryStringEncoding
{
get
{
Encoding contentEncoding = this.ContentEncoding;
if (!contentEncoding.Equals(Encoding.Unicode))
{
return contentEncoding;
}
return Encoding.UTF8;
}
}
Следуя пути, чтобы узнать this.ContentEncoding приводит вас (также в HttpRequest)
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);
}
}
Чтобы ответить на ваш конкретный вопрос о разности betwen Request.Url.Quer и Request.QueryString... вот как HttpRequest строит свое свойство Url:
public Uri Url
{
get
{
if ((this._url == null) && (this._wr != null))
{
string queryStringText = this.QueryStringText;
if (!string.IsNullOrEmpty(queryStringText))
{
queryStringText = "?" + HttpEncoder.CollapsePercentUFromStringInternal(queryStringText, this.QueryStringEncoding);
}
if (AppSettings.UseHostHeaderForRequestUrl)
{
string knownRequestHeader = this._wr.GetKnownRequestHeader(0x1c);
try
{
if (!string.IsNullOrEmpty(knownRequestHeader))
{
this._url = new Uri(this._wr.GetProtocol() + "://" + knownRequestHeader + this.Path + queryStringText);
}
}
catch (UriFormatException)
{
}
}
if (this._url == null)
{
string serverName = this._wr.GetServerName();
if ((serverName.IndexOf(':') >= 0) && (serverName[0] != '['))
{
serverName = "[" + serverName + "]";
}
this._url = new Uri(this._wr.GetProtocol() + "://" + serverName + ":" + this._wr.GetLocalPortAsString() + this.Path + queryStringText);
}
}
return this._url;
}
}
Вы можете увидеть, что для выполнения декодирования используется класс HttpEncoder, но он использует одно и то же значение QueryStringEncoding.
Так как я уже размещаю здесь много кода, и любой может получить .NET Reflector, я собираюсь отредактировать все остальное. Свойство QueryString происходит из HttpValueCollection, который использует метод FillFromEncodedBytes, чтобы в конечном итоге вызвать HttpUtility.UrlDecode(с установленным выше значением QueryStringEncoding), которое в конечном итоге вызывает HttpEncoder для его декодирования.
Кажется, что они используют другую методологию для декодирования фактических байтов запроса, но кодировка, которую они используют для этого, кажется одинаковой.
Мне интересно, что у HttpEncoder есть так много функций, которые, похоже, делают одно и то же, поэтому возможно наличие различий в тех методах, которые могут вызвать проблему.