简体   繁体   English

Request.Url.Query和Request.QueryString有什么区别?

[英]What's the difference between Request.Url.Query and Request.QueryString?

I have been tracking down a bug on a Url Rewriting application. 我一直在追踪Url重写应用程序的错误。 The bug showed up as an encoding problem on some diacritic characters in the querystring. 该错误显示为查询字符串中某些变音字符的编码问题。

Basically, the problem was that a request which was basically /search.aspx?search=heřmánek was getting rewritten with a querystring of "search=he%c5%99m%c3%a1nek" 基本上,问题是基本上是/search.aspx?search=heřmánek的请求被重写了“search = he%c5%99m%c3%a1nek”的查询字符串

The correct value (using some different, working code) was a rewrite of the querystring as "search=he%u0159m%u00e1nek" 正确的值(使用一些不同的工作代码)是将查询字符串重写为“search = he%u0159m%u00e1nek”

Note the difference between the two strings. 注意两个字符串之间的区别。 However, if you post both you'll see that the Url Encoding reproduces the same string. 但是,如果您同时发布,则会看到Url Encoding会重现相同的字符串。 It's not until you use the context.Rewrite function that the encoding breaks. 直到你使用编码中断的context.Rewrite函数。 The broken string returns 'heÅmánek' (using Request.QueryString["Search"] and the working string returns 'heřmánek'. This change happens after the call to the rewrite function. 断开的字符串返回'heÅmánek'(使用Request.QueryString [“Search”],工作字符串返回'heřmánek'。这个改变发生在调用重写函数之后。

I traced this down to one set of code using Request.QueryString (working) and the other using Request.Url.Query (request.Url returns a Uri instance). 我使用Request.QueryString(工作)将其追溯到一组代码,另一个使用Request.Url.Query(request.Url返回一个Uri实例)。

While I have worked out the bug there is a hole in my understanding here, so if anyone knows the difference, I'm ready for the lesson. 虽然我已经解决了这个问题,但我的理解还有一个漏洞,所以如果有人知道这个差异,我已经准备好上课了。

Your question really sparked my interest, so I've done some reading for the past hour or so. 你的问题确实引起了我的兴趣,所以我在过去一小时左右做了一些阅读。 I'm not absolutely positive I've found the answer, but I'll throw it out there to see what you think. 我并不是绝对肯定我找到了答案,但我会把它扔出去看看你的想法。

From what I've read so far, Request.QueryString is actually "a parsed version of the QUERY_STRING variable in the ServerVariables collection" [reference] , where as Request.Url is (as you stated) the raw URL encapsulated in the Uri object. 从我到目前为止所读到的,Request.QueryString实际上是“ServerVariables集合中的QUERY_STRING变量的解析版本” [reference] ,其中Request.Url(如你所述)封装在Uri对象中的原始URL 。 According to this article , the Uri class' constructor "...parses the [url string], puts it in canonical format, and makes any required escape encodings." 根据这篇文章 ,Uri类的'构造函数'...解析[url string],将其置于规范格式,并进行任何必需的转义编码。“

Therefore, it appears that Request.QueryString uses a different function to parse the "QUERY_STRING" variable from the ServerVariables constructor. 因此,看起来Request.QueryString使用不同的函数来解析ServerVariables构造函数中的“QUERY_STRING”变量。 This would explain why you see the difference between the two. 这可以解释为什么你看到两者之间的差异。 Now, why different encoding methods are used by the custom parsing function and the Uri object's parsing function is entirely beyond me. 现在,为什么自定义解析函数使用不同的编码方法,而Uri对象的解析函数完全超出我的范围。 Maybe somebody a bit more versed on the aspnet_isapi DLL could provide some answers with that question. 也许有人对aspnet_isapi DLL有点精通,可以为这个问题提供一些答案。

Anyway, hopefully my post makes sense. 无论如何,希望我的帖子有意义。 On a side note, I'd like to add another reference which also provided for some very thorough and interesting reading: http://download.microsoft.com/download/6/c/a/6ca715c5-2095-4eec-a56f-a5ee904a1387/Ch-12_HTTP_Request_Context.pdf 在旁注中,我想添加另一个参考资料,该参考资料还提供了一些非常全面和有趣的阅读: http//download.microsoft.com/download/6/c/a/6ca715c5-2095-4eec-a56f- a5ee904a1387 / CH-12_HTTP_Request_Context.pdf

What you indicated as the "broken" encoded string is actually the correct encoding according to standards. 根据标准,您表示为“损坏”的编码字符串实际上是正确的编码。 The one that you indicated as "correct" encoding is using a non-standard extension to the specifications to allow a format of %uXXXX (I believe it's supposed to indicate UTF-16 encoding). 您指定为“正确”编码的那个使用规范的非标准扩展,以允许格式为%uXXXX (我相信它应该表示UTF-16编码)。

In any case, the "broken" encoded string is ok. 在任何情况下,“破损”编码的字符串都可以。 You can use the following code to test that: 您可以使用以下代码来测试:

Uri uri = new Uri("http://www.example.com/test.aspx?search=heřmánek");
Console.WriteLine(uri.Query);
Console.WriteLine(HttpUtility.UrlDecode(uri.Query));

Works fine. 工作良好。 However... on a hunch, I tried UrlDecode with a Latin-1 codepage specified, instead of the default UTF-8: 但是......在预感中,我尝试使用指定的Latin-1代码页的UrlDecode,而不是默认的UTF-8:

Console.WriteLine(HttpUtility.UrlDecode(uri.Query, 
           Encoding.GetEncoding("iso-8859-1")));

... and I got the bad value you specified, 'heÅmánek'. ......我得到了你指定的坏价值,'heÅmánek'。 In other words, it looks like the call to HttpContext.RewritePath() somehow changes the urlencoding/decoding to use the Latin-1 codepage, rather than UTF-8, which is the default encoding used by the UrlEncode/Decode methods. 换句话说,看起来对HttpContext.RewritePath()的调用以某种方式改变urlencoding / decoding以使用Latin-1代码页,而不是UTF-8,这是UrlEncode / Decode方法使用的默认编码。

This looks like a bug if you ask me. 如果你问我,这看起来像个错误。 You can look at the RewritePath() code in reflector and see that it is definitely playing with the querystring - passing it around to all kinds of virtual path functions, and out to some unmanaged IIS code. 您可以查看反射器中的RewritePath()代码,看看它是否正在使用查询字符串 - 将其传递给所有类型的虚拟路径函数,以及一些非托管的IIS代码。

I wonder if somewhere along the way, the Uri at the core of the Request object gets manipulated with the wrong codepage? 我想知道在某个地方,请求对象核心的Uri是否被错误的代码页操纵? That would explain why Request.Querystring (which is simply the raw values from the HTTP headers) would be correct, while the Uri using the wrong encoding for the diacriticals would be incorrect. 这可以解释为什么Request.Querystring (它只是来自HTTP头的原始值)是正确的,而使用错误编码的变量的Uri将是不正确的。

I have done a bit of research over the past day or so and I think I have some information on this. 我在过去一天左右做了一些研究,我想我有一些相关信息。

When you use Request.Querystring or HttpUtility.UrlDecode (or Encode) it is using the Encoding that is specified in the element (specifically the requestEncoding attribute) of the web.config (or the .config hierarchy if you haven't specified) ---NOT the Encoding.Default which is the default encoding for your server. 当您使用Request.Querystring或HttpUtility.UrlDecode(或Encode)时,它使用web.config(或.config层次结构,如果您未指定)的元素(特别是requestEncoding属性)中指定的编码 - - 不是Encoding.Default,它是服务器的默认编码。

When you have the encoding set to UTF-8, a single unicode character can be encoded as 2 %xx hex values. 如果将编码设置为UTF-8,则可以将单个unicode字符编码为2%xx十六进制值。 It will also be decoded that way when given the whole value. 当给定整个值时,它也将以这种方式解码。

If you are UrlDecoding with a different Encoding than the url was encoded with, you will get a different result. 如果您使用与编码的网址不同的编码进行UrlDecoding,则会得到不同的结果。

Since HttpUtility.UrlEncode and UrlDecode can take an encoding parameter, its tempting to try to encode using an ANSI codepage, but UTF-8 is the right way to go if you have the browser support (apparently old versions don't support UTF-8). 由于HttpUtility.UrlEncode和UrlDecode可以采用编码参数,因此很容易尝试使用ANSI代码页进行编码,但如果您拥有浏览器支持,则UTF-8是正确的方法(显然旧版本不支持UTF-8) )。 You just need to make sure that the is properly set and both sides will work fine. 您只需要确保正确设置并且双方都能正常工作。

UTF-8 Seems to be the default encoding: (from .net reflector System.Web.HttpRequest) UTF-8似乎是默认编码:(来自.net反射器System.Web.HttpRequest)

internal Encoding QueryStringEncoding
{
    get
    {
        Encoding contentEncoding = this.ContentEncoding;
        if (!contentEncoding.Equals(Encoding.Unicode))
        {
            return contentEncoding;
        }
        return Encoding.UTF8;
    }
}

Following the path to find out the this.ContentEncoding leads you to (also in HttpRequest) 按照路径找出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);
    }
}

To answer your specific question on the difference betwen Request.Url.Quer and Request.QueryString... here is how HttpRequest builds its Url Property: 回答你关于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;
    }
}

You can see it is using the HttpEncoder class to do the decoding, but it uses the same QueryStringEncoding value. 您可以看到它使用HttpEncoder类进行解码,但它使用相同的QueryStringEncoding值。

Since I am already posting a lot of code here and anyone can get .NET Reflector, I'm going to snippet up the rest. 由于我已经在这里发布了很多代码,并且任何人都可以获得.NET Reflector,我将要完成其余部分。 The QueryString property comes from the HttpValueCollection which uses FillFromEncodedBytes method to eventually call HttpUtility.UrlDecode (with the QueryStringEncoding value set above), which eventually calls the HttpEncoder to decode it. QueryString属性来自HttpValueCollection,它使用FillFromEncodedBytes方法最终调用HttpUtility.UrlDecode(上面设置了QueryStringEncoding值),最终调用HttpEncoder对其进行解码。 They do seem to use different methodology to decode the actual bytes of the querystring, but the encoding they use to do it seems to be the same. 他们似乎使用不同的方法来解码查询字符串的实际字节,但他们用来做它的编码似乎是相同的。

It is interesting to me that the HttpEncoder has so many functions that seem to do the same thing, so its possible there are differences in those methods which can cause an issue. 有趣的是,HttpEncoder有很多功能似乎做同样的事情,因此可能导致问题的那些方法存在差异。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM