【发布时间】: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