IIS7、RewritePath 和 IIS 日志文件

Posted

技术标签:

【中文标题】IIS7、RewritePath 和 IIS 日志文件【英文标题】:IIS7, RewritePath and IIS log files 【发布时间】:2010-09-26 02:17:47 【问题描述】:

我在 IIS7 上运行的 ASP.NET 3.5 应用程序中使用 Context.RewritePath()。

我在应用程序 BeginRequest 事件中执行此操作,并且一切正常文件。

对 /sports 的请求被正确地重写为 default.aspx?id=1,依此类推。

问题在于,在我的 IIS 日志中,我看到 GET 请求是针对 /Default.aspx?id=1 而不是针对 /sports。

这种代码在 IIS6 下完美运行。

由于必须实现一些业务逻辑,因此不能选择使用 Microsoft Rewrite 模块。

谢谢。

编辑:

似乎我的处理程序在管道中为时过早,但如果我将逻辑移至稍后的事件,那么整个重写操作将不起作用(为时已晚,StaticFileHandler 会接收我的请求)。

我用谷歌搜索和搜索,四处询问,不敢相信没有人有这个问题?

编辑:

哎呀!这是我在 IIS 论坛上找到的:

“这是因为在集成模式下,IIS 和 asp.net 共享一个公共管道,并且 RewritePath 现在被 IIS 看到,而在 IIS6 中,它甚至没有被 IIS 看到 - 您可以通过使用经典模式来解决这个问题会表现得像 IIS6。”

最终更新:请看my answer below,我在生产环境一年多后更新了结果。

【问题讨论】:

我会(并且已经)通过反射器查看 System.Web.Routing 程序集。看看在哪里连接它。 IIRC,您需要在 PostMapRequestHandler 和 PostAcquireRequestState 处进行。 我确实尝试过,正如我在编辑中所写的那样,但该事件在管道中为时已晚...... 我重读了您的更新。有没有办法在应用程序的某处附加事件处理程序?我的意思是请求必须在某个地方结束。我的自定义重写实验也被证明是困难的。 我尝试了几乎所有的事件。要么我失去日志记录,要么重写太晚,要么我失去会话状态...... :(我不敢相信没有人有这些问题? Muerte,正确的做法是回答你自己的问题。您说通过将 IIS 7 置于经典模式可以解决此问题,该模式的执行方式与 IIS 6 相同。只要您意识到这样做不会从新 IIS 7 中的安全性或性能升级中受益这似乎是一个合理的答案。 【参考方案1】:

您可以在处理请求后但在 IIS 日志记录模块写入日志条目之前将路径设置回原始值。

例如,此模块重写BeginRequest 上的路径,然后将其设置回EndRequest 上的原始值。使用此模块时,原始路径会出现在 IIS 日志文件中:

public class RewriteModule : IHttpModule

    public void Init(HttpApplication context)
    
        context.BeginRequest += OnBeginRequest;
        context.EndRequest += OnEndRequest;
    

    static void OnBeginRequest(object sender, EventArgs e)
    
        var app = (HttpApplication)sender;
        app.Context.Items["OriginalPath"] = app.Context.Request.Path;
        app.Context.RewritePath("Default.aspx?id=1");
    

    static void OnEndRequest(object sender, EventArgs e)
    
        var app = (HttpApplication)sender;
        var originalPath = app.Context.Items["OriginalPath"] as string;
        if (originalPath != null)
        
            app.Context.RewritePath(originalPath);
        
    

    public void Dispose()
    

    

【讨论】:

是的,我已经在 Vista 上使用 IIS 7 对其进行了测试,并检查了网页是否看到了重写的路径,但原始路径是否已写入 IIS 日志文件。但我还没有对这样做可能产生的副作用进行任何详细的测试。【参考方案2】:

我也遇到过同样的问题。解决此问题的一种方法是使用 Server.Transfer 而不是 Context.RewritePath。 Server.Transfer 不会重新启动整个页面生命周期,因此仍会记录原始 URL。请务必为“preserveForm”参数传递“true”,以便 QueryString 和 Form 集合可用于第二页。

【讨论】:

【参考方案3】:

经过一番研究,我终于找到了解决问题的方法。

我已经用新的(在 ASP.NET 3.5 中引入)Context.Server.TransferRequest() 方法替换了对 Context.RewritePath() 方法的调用。

现在看起来很明显,但 IIS 核心团队的高级开发工程师没有想到这一点。

我已经针对会话、身份验证、回发、查询字符串等问题对其进行了测试,但没有发现任何问题。

明天我会将更改部署到一个流量非常大的站点,我们很快就会知道它的实际工作原理。 :)

我会回来更新的。

更新:该解决方案仍未完全在我的生产服务器上,但它已经过测试并且确实有效,据我所知,它是我的问题的解决方案。如果我在生产中发现任何其他内容,我会发布更新。

最终更新:我在生产中使用了这个解决方案一年多了,它已被证明是一个良好且稳定的解决方案,没有任何问题。

【讨论】:

为什么看起来这么明显?【参考方案4】:

老问题,但是当我执行以下操作时,我发现我没有遇到您的问题:

a) web.config 中的重写规则,用于将所有请求定向到 /default.aspx,例如:

    <rule name="all" patternSyntax="Wildcard" stopProcessing="true">
      <match url="*"/>
      <action type="Rewrite" url="/default.aspx"/>
    </rule>

b) 在 default.aspx 的 Page_PreInit 事件中调用 RewritePath,将 URL 和查询字符串重写为请求中传递的内容(即不存在的位置)。

例如,我请求“/somepage/?x=y”(不存在)。

a) Web.config 规则将其映射到 /default.aspx

b) Page_PreInit 将其重写为“/somepage/?x=y”。

这样做的结果,在 IIS 7(Express 和生产)中,服务器日志反映了存根的“/somepage”和查询的“x=y”,并且所有请求对象属性都反映了请求(不存在) URL(这是我想要的)。

唯一奇怪的效果是,在 IIS Express 中,日志项被写入了两次。但是,这不会在生产环境中发生(Windows Server 2008 R2)。

【讨论】:

以上是关于IIS7、RewritePath 和 IIS 日志文件的主要内容,如果未能解决你的问题,请参考以下文章

如何分析IIS7的失败请求跟踪日志

IIS 7 日志记录 Web 服务方法

IIS7 的 UnauthorizedAccessException

远程桌面复制粘贴—IIS7远程桌面程序功能大全

iis7应用程序池自动停止 HTTP Error 503. The service is unavailable.

IIS6.0 IIS7.5应用程序池自动停止的解决方法