在IIS HttpModule中修改HttpRequest的POST内容是否可行?

8
我需要修改IIS中某些Http请求(SSAS连接字符串)的内容。基本上,我需要向请求中包含的SOAP添加一个元素。
到目前为止,我的方法是向HttpRequest添加一个过滤器,并在过滤器的Read方法中执行更改。就我所知,Read从未被执行过。
我的理解是,当IIS处理请求时,Request.Filter会被读取,因此IIS应该看到我的修改后的请求。
使用HttpModule实现这个功能是否可行?我的过滤器方法是否正确?
如果是这样,请问是什么原因导致Read没有被命中?
以下是我的代码简化版本:

public class CustomHttpModule : IHttpModule {
    private HttpApplication app;
    public string ModuleName {
        get { return "CustomHttpModule"; }
    }
    public void Init(HttpApplication context) {
        app = context;
        context.PreRequestHandlerExecute += new EventHandler(context_PreRequestHandlerExecute);
    }
    void context_PreRequestHandlerExecute(object sender, EventArgs e) {
        var request = app.Context.Request;
        request.Filter = new CustomHttpFilter(request.Filter);
    }
}

public class CustomHttpFilter : Stream {
    private Stream outputStream;
    public CustomHttpFilter(Stream outputFilter) {
        outputStream = outputFilter;
    }
    public override int Read(byte[] buffer, int offset, int count) {
        // read and make the necessary changes
    }
}

我有一个类似的问题。你采取了哪种方法?你使用反射来启用对请求对象的写入,还是实现了一个请求过滤器? - Ryan Taylor
3个回答

4

实际上,通过HttpModule在IIS 7.0+中可以修改HttpRequest POST的内容。我曾经遇到这个问题并且成功解决了它。我发布这篇文章是为了以后的参考,因为没有多少文章详细说明它何时/为什么会或不会起作用。

以下是故障排除的检查清单:

  1. 确保您的模块以及其他模块没有以使其在将过滤器添加到请求过滤器之前评估输入流的方式访问Request对象。例如,访问Request.Form["param"]将触发输入流的评估。其中一种症状是您的过滤器的Read方法从未被调用。

  2. 查看统一的IIS管道中事件的顺序https://msdn.microsoft.com/en-us/library/bb470252.aspx。您会发现PreRequestHandlerExecute事件发生在第12个引发的事件之后。为了有最好的机会设置请求过滤器并使其应用,您应该在BeginRequest事件中这样做,它是请求验证和URL映射之后的第一个事件(在HttpModule中公开,还有其他在ISAPI扩展或过滤器中公开的事件)。ISAPI过滤器和扩展程序确实具有可能在HttpModule事件之前发生的某些事件,但是由于

  3. 请考虑Request.Filter是一系列流,它们按顺序评估,将一个流的输出传递给下一个流的输入,它们也可以在您的模块接收输入之前修改请求。如果出现某些奇怪的行为,请考虑删除一些其他过滤器以隔离问题或更改它们加载的顺序。

  4. 还要考虑您的Stream过滤器的Read和Write方法是按块调用的,因此它们可能会被多次调用,具有不同的偏移量,因此请确保您的重写逻辑正常工作,特别是如果您正在替换内容导致不同的请求或响应大小,请参见下面。

  5. 如果您在Read或Write中执行搜索/替换,则需要考虑您的数据可能跨越多个读取/写入。在这种情况下,您可能希望考虑在MemoryStream中缓冲请求或响应流,并在其中操作。

如果将问题隔离并简化到最基本的情况,最终您将确定导致其无法工作的原因。这里提供的简单示例演示了https://msdn.microsoft.com/en-us/library/system.web.httprequest.filter.aspx,但它并未演示如何在缓冲流上操作。
我已经编写了一个示例,演示了一个用于参考的缓冲请求和响应重写HttpModule。https://github.com/snives/HttpModuleRewrite

那个 GitHub 的示例正是我所需要的! - DiskJunky
似乎GitHub示例仅在ContentType为“x-www-form-urlencoded”且端点以.aspx结尾时才有效。即使我删除GitHub示例中检查是否以.aspx结尾的if语句,它也不适用于其他扩展名。有任何想法为什么? - Jesper Lundin
@JesperLundin 可能有很多原因:配置不当、安全性、身份验证、授权、映射、处理程序、权限、重写规则、运行时、事件等。首先确保 IIS 处理程序映射设置为调用 ASP.NET 运行时以处理这些请求。除此之外,我建议您学习 IIS 请求管道架构 https://learn.microsoft.com/en-us/iis/get-started/introduction-to-iis/introduction-to-iis-architecture - Snives

1
可以通过覆盖WorkerRequest实现。您可以像下面这样获取当前的工作请求:
(HttpWorkerRequest)context.GetService(typeof(HttpWorkerRequest))

您可以通过引用IIS7WorkerRequest.cs .net参考源代码来实现派生工作程序请求。

困难的部分是从输入流中读取所有字节并解析数据。您应该了解HTTP多部分表单数据规范。


0

我认为使用http模块修改请求(request)是不可能的,但是可以修改响应(response)HttpRequest对象大多是只读的,因此在任何情况下都是不可变的,而不仅仅是从模块中。

如果你真的很绝望,你可以尝试使用反射(reflection)来访问更多的http请求对象。然而,要访问、修改或调用非公共成员,您的进程需要完全信任(full trust)权限,这在Web环境中非常危险


1
这是不正确的。在某些情况下,可以使用HttpModule实现HttpRequest.Filter来修改入站http负载。 以下是有人成功的示例  https://dev59.com/90_Sa4cB1Zd3GeqP8wod - Mark Arnott

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接