最近我的团队被要求为 ASP.NET MVC 应用程序实现一个 HttpModule,该应用程序处理 IIS 7 和 .NET 3.5 上的双重编码 URL。这是问题的关键:
我们有时会收到具有双重编码正斜杠的 URL,如下所示:
http://www.example.com/%252fbar%5cbaz/foo
我们还必须处理其他格式,但它们都有一些共同点,它们都有一个双编码正斜杠。
为了解决这个问题,我们编写了一个 HttpModule,它仅在 URL 具有双编码正斜杠时才起作用,我们将其重定向到一个合理的 URL。细节并不重要,但有两点是:
- 我们无法控制这些 URL 具有双重编码的正斜杠这一事实
- 我们还没有升级到 .NET 4.0,也不在近期内。
问题是:
IIS 启动后的第一个请求显示与第二个请求不同的 URL。
如果我们使用上述示例中的 URL,对 IIS 的第一个请求将如下所示:
http://www.example.com/bar/baz/foo
第二个请求看起来像:
http://www.example.com/%252fbar%5cbaz/foo
这是通过在调试时检查 Application.Request.Url.AbsolutePath
属性来完成的。
这是应该重现问题的最小代码示例(创建一个新的 MVC 应用程序,并注册以下 HttpModule):
public class ForwardSlashHttpModule : IHttpModule
{
internal IHttpApplication Application { get; set; }
public void Dispose()
{
Application = null;
}
public void Init(HttpApplication context)
{
Initialize(new HttpApplicationAdapter(context));
}
internal void Initialize(IHttpApplication context)
{
Application = context;
context.BeginRequest += context_BeginRequest;
}
internal void context_BeginRequest(object sender, EventArgs e)
{
var url = Application.Request.Url.AbsolutePath; //<-- Problem point
//Do stuff with Url here.
}
}
然后,在本地主机上调用相同的 URL:
http://www.example.com/%252fbar%5c/foo
NB: Make sure to insert a
Debugger.Launch()
call before the line incontext_BeginRequest
so that you'll be able to see it the first time IIS launches
当你执行第一个请求时,你应该看到:
http://example.com/bar/foo
在后续请求中,您应该看到:
http://example.com//bar/foo
。
我的问题是:这是 IIS 中的错误吗?为什么它在第一次调用 Application.Request.Url.AbsolutePath
时提供不同的 URL,但对于任何后续请求都不提供?
此外:第一个请求是否针对双重编码的 URL 并不重要,第二个请求将始终由 IIS 适本地处理(或者至少,尽可能适本地处理双重编码的正斜杠) .问题出在第一个请求上。
更新
我尝试了几个不同的属性,看看在第一次请求时是否有不同的值:
第一次请求string u = Application.Request.Url.AbsoluteUri;
"http://example.com/foo/baz/bar/"
string x = Application.Request.Url.OriginalString;
"http://example.com:80/foo/baz/bar"
string y = Application.Request.RawUrl;
"/%2ffo/baz/bar"
bool z = Application.Request.Url.IsWellFormedOriginalString();
true
唯一有趣的是 Application.Request.RawUrl
发出一个单编码的正斜杠 (%2f
),并转换编码的反斜杠 ( %5c
) 到正斜杠(尽管其他所有内容也是如此)。
RawUrl
在第一次请求时仍然是部分编码的。
string u = Application.Request.Url.AbsoluteUri;
"http://example.com//foo/baz/bar"
string x = Application.Request.Url.OriginalString;
"http://example.com:80/%2ffoo/baz/bar"
string y = Application.Request.RawUrl;
"/%2ffoo/baz/bar"
bool z = Application.Request.Url.IsWellFormedOriginalString();
false
第二个请求的有趣点:
IsWellFormedOriginalString()
为false
。在第一个请求中,它是true
。- RawUrl 相同(可能有帮助)。
AbsoluteUri
不同。在第二个请求中,它有两个正斜杠。
更新
Application.Request.ServerVariables["URL"] = /quotes/gc/v12/CMX
Application.Request.ServerVariables["CACHE_URL"] = http://example.com:80/%2ffoo/baz/bar
开放式问题
- 这似乎是 IIS 或 .NET 中的错误。是吗?
- 这仅对应用程序在
iisreset
之后发出的第一个请求有影响
- 除了使用 RawUrl(因为如果我们解析 Raw Url 而不是使用 .NET 提供的“安全”URL,我们将不得不担心很多其他问题),我们还有什么其他方法可以处理这个问题?
请记住,这个问题的物理影响很小:要成为一个实际问题,客户端对 Web 服务器的第一个请求必须针对上述特定 URL,并且发生这种情况的可能性很大相对较低。
最佳答案
Request.Url 已经可以被解码 - 我不会相信你在做什么。
查看内部详细信息: Querystring with url-encoded ampersand prematurely decoded within Request.Url
解决方案是直接通过 Request.RawUrl 访问这些值。
我知道你的问题出在路径上,但似乎发生了同样的事情。试试 RawUrl - 看看它是否适合你。
关于c# - IIS 在第一个请求和后续请求中以不同方式处理 URL 中的双编码正斜杠,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7251285/