Подтвердить что ты не робот

Какая разница между 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).

Пока я выработал ошибку, в моем понимании есть дыра, поэтому, если кто-то знает разницу, я готов к уроку.

4b9b3361

Ответ 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 есть так много функций, которые, похоже, делают одно и то же, поэтому возможно наличие различий в тех методах, которые могут вызвать проблему.