【问题标题】:Modify POST request with a custom HttpModule and a HttpRequest filter使用自定义 HttpModule 和 HttpRequest 过滤器修改 POST 请求
【发布时间】:2021-07-29 14:49:18
【问题描述】:

我想修改所有到达 web api 的请求内容。我无法更改 web api 中的代码,而是添加带有请求过滤器的 HttpModule。我尝试使用以下答案 https://stackoverflow.com/a/35590493/5901959 中的 repo。

这里是RequestFilter中Read方法的简化版,

public override int Read(byte[] buffer, int offset, int count)
{            
    if (ms == null)
    {
        var sr = new StreamReader(_stream, _encoding);
        string content = sr.ReadToEnd();

        content = content.ToUpper().Substring(0, 3);

        byte[] bytes = _encoding.GetBytes(content);
        ms = new MemoryStream();
        ms.Write(bytes, 0, bytes.Length);
        ms.Seek(0, SeekOrigin.Begin);
    } 

    return ms.Read(buffer, offset, count);
}

这在 web api 中给出了以下错误,

Exception System.AggregateException: One or more errors occurred. ---> System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values.
Parameter name: offset
   at System.Web.HttpInputStream.Seek(Int64 offset, SeekOrigin origin)
   at System.Web.Http.WebHost.SeekableBufferedRequestStream.SwapToSeekableStream()
   at System.Web.Http.WebHost.SeekableBufferedRequestStream.EndRead(IAsyncResult asyncResult)
   at System.Net.Http.StreamToStreamCopy.StartRead()
   --- End of inner exception stack trace ---
   at System.Threading.Tasks.Task`1.GetResultCore(Boolean waitCompletionNotification)
   at Echo.Controllers.EchoController.Echo() in C:\repos-test\HttpModule to change request body\Echo\Echo\Controllers\EchoController.cs:line 23
---> (Inner Exception #0) System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values.
Parameter name: offset
   at System.Web.HttpInputStream.Seek(Int64 offset, SeekOrigin origin)
   at System.Web.Http.WebHost.SeekableBufferedRequestStream.SwapToSeekableStream()
   at System.Web.Http.WebHost.SeekableBufferedRequestStream.EndRead(IAsyncResult asyncResult)
   at System.Net.Http.StreamToStreamCopy.StartRead()<---

我添加了日志记录,我可以看到调用了 Read 方法,但没有调用错误指示的 Seek 方法。

如果我删除 .Substring(0, 3) 则不会引发异常,但 web api 会获取原始请求,该请求是小写的,因此不是修改后的请求。看起来 HttpInputStream 从未改变过。

================== 编辑 =========================
我创建了一个小型 Web API 来进一步测试它。似乎如果我在 WebAPI 中从 InputStream 读取两次,第一次读取返回原始响应,第二次读取返回由过滤器创建的响应。例如,如果将 RequestFilter 中的内容更改为大写,不带子字符串部分,然后在 web api 中使用以下代码,payload="This is my payload"

Stream stream = Request.Content.ReadAsStreamAsync().Result;
StreamReader sr = new StreamReader(stream);
string s = sr.ReadToEnd();
log.Info(s); // This gives: This is my payload

stream.Seek(0, SeekOrigin.Begin);
s = sr.ReadToEnd();
log.Info(s); // This gives: THIS IS MY PAYLOAD

stream.Seek(0, SeekOrigin.Begin);
s = sr.ReadToEnd();
log.Info(s); // This gives: THIS IS MY PAYLOAD

我也尝试在 HttpModule 的请求过滤器中设置 content="Something fully different",结果相似 =>

第一次阅读 =“这是我的有效载荷”,
第二次阅读=“完全不同的东西”。

一个流如何包含两个不同的内容?


编辑 2021-05-25

我发现要让它工作,端点需要以 .aspx 结尾,并且请求的内容类型必须是“x-www-form-urlencoded”。

问题:

  • 谁能解释为什么它必须是特定的内容类型和扩展名?
  • 是否可以为不以 .aspx 结尾的端点进行这项工作?

编辑 2021-05-27

添加请求过滤器后,我添加了以下行,

var _ = context.Request.Form;

触发输入流的评估。然后,如果内容类型是“x-www-form-urlencoded”,则将应用请求过滤器。如果您有任何其他类型的数据,如 json、xml、原始文本,那么请求内容不会因某种原因而改变。也许请求过滤器仅适用于表单数据?

【问题讨论】:

    标签: c# asp.net iis httprequest httpmodule


    【解决方案1】:

    我建议你调试Substring(0, 3)这部分代码,错误AggregateException shuold由你试图提取一个超出当前字符串范围的子字符串引起。

    提取子串的方法都要求你指定子串的起始位置,对于不延续到串尾的子串,指定子串中的字符数。

    【讨论】:

      猜你喜欢
      • 2011-03-15
      • 2018-12-30
      • 2015-01-23
      • 2011-03-04
      • 2010-11-27
      • 1970-01-01
      • 1970-01-01
      • 2020-11-14
      • 1970-01-01
      相关资源
      最近更新 更多