C# 如何使用自定义IHttpModule和HttpRequest筛选器修改POST请求?

C# 如何使用自定义IHttpModule和HttpRequest筛选器修改POST请求?,c#,asp.net,iis,iis-7,httpmodule,C#,Asp.net,Iis,Iis 7,Httpmodule,概述 我希望能够将请求参数和内容修改为第三方web服务(ArcGIS服务器)。这将用于创建存在于任何客户端应用程序和服务器应用程序之间的安全层 我认为我已经找到了解决办法,但我目前在实施过程中遇到了一些困难 潜在解决方案:使用自定义请求筛选器修改请求 对于解决方案,我实现了一个自定义请求过滤器,该过滤器松散地基于。我已经“增强”了代码,以便可以使用正则表达式搜索和替换必要的内容。这包括: 将内容(存储在字节数组中)转换为字符串 搜索字符串并执行任何必要的修改 将修改后的字符串转换为字节数组并将其

概述

我希望能够将请求参数和内容修改为第三方web服务(ArcGIS服务器)。这将用于创建存在于任何客户端应用程序和服务器应用程序之间的安全层

我认为我已经找到了解决办法,但我目前在实施过程中遇到了一些困难

潜在解决方案:使用自定义请求筛选器修改请求

对于解决方案,我实现了一个自定义请求过滤器,该过滤器松散地基于。我已经“增强”了代码,以便可以使用正则表达式搜索和替换必要的内容。这包括:

  • 将内容(存储在字节数组中)转换为字符串
  • 搜索字符串并执行任何必要的修改
  • 将修改后的字符串转换为字节数组并将其写入缓冲区
  • 示例如下所示:

    public override int Read(byte[] buffer, int offset, int count)
    {
        int bytesRead = _stream.Read(buffer, offset, count);
    
        string orgContent = Encoding.UTF8.GetString(buffer, offset, bytesRead);
        string orgContentDecoded = HttpUtility.UrlDecode(orgContent);
        
        string layersPattern = @"&layers=(show|hide|include|exclude):([0-9]+,?)+";
        Regex layersRegex = new Regex(layersPattern, RegexOptions.IgnoreCase);
        
        string[] permittedLayers = new string[] { "0" , "1" };
        string replacementLayers = "&layers=show:" + String.Join(",", permittedLayers);
        string newContentDecoded = layersRegex.Replace(orgContentDecoded, replacementLayers);
        
        string newContent =  newContentDecoded.Replace(",", "%2C").Replace(":", "%3A");
    
        byte[] newBuffer = Encoding.UTF8.GetBytes(newContent);
        int newByteCountLength = Encoding.UTF8.GetByteCount(newContent);
        
        Encoding.UTF8.GetBytes(newContent, 0, Encoding.UTF8.GetByteCount(newContent), buffer, 0);
        
        return bytesRead;
    }
    
    只要修改后的内容长度与原始内容长度相同,这似乎效果良好。例如,如果我将1替换为2,一切都会正常。但是,如果我将1替换为10(从而将消息大小增加1),那么我将收到来自ArcGIS Server的错误,该格式不受支持

    这引起了我的两个关注:

  • 当前实现不处理分块请求。也就是说,如果请求sie足够大,则可以针对单个请求多次调用Read在这种情况下应该如何处理分块?
  • 错误消息的根本原因是什么?问题是否与内容长度与流长度不同有关如何正确修改内容,使其长度不受影响?

  • 有什么想法吗?

    这个问题第二部分的答案是返回修改后的内容大小,而不是原始流的大小。瞧

    // return bytesRead;
    return newByteCountLength;
    

    这个问题和您的答案对我来说非常有用,但是如果您试图向流中插入大量数据,那么答案并不是全部:

    仅当插入到流中的数据不会将读入缓冲区的字节数超过
    计数
    值时,返回修改后的内容大小才有效。如果您试图插入太多数据,您可能会发现
    缓冲区
    对象不够大,无法容纳您插入的数据,或者通过向缓冲区写入超过
    计数
    字节的数据,您正在覆盖缓冲区末端的一些数据,而这些数据本来是单独保留的


    如果需要插入的数据超过当前
    缓冲区
    对象所能容纳的数据量,则必须将数据缓冲在单独的字节数组中,并在调用
    stream.read
    时将其分块复制。

    如Chris McKeown所述,除非您承诺不修改数据的大小,否则这并不是最好的过滤技术。为了这个答案的完整性,我发布了一个示例项目,演示了如果您感兴趣,如何使用缓冲技术过滤请求和响应

    此外,对于与HttpModules的故障排除相关的问题,这篇文章也非常有帮助