问题描述
我正在尝试编写一个 HttpModule,它会在请求正文到达 RestAPI 之前更改它。目标是在内容类型为“x-www-form-urlencoded”的请求正文中添加一些键值。我的第一次尝试是仅将有效负载中的字符更改为大写。为了测试这一点,将 httpmodule 添加到一个简单的 restapi 中,它在响应中返回请求内容。 httpmodule 的日志显示请求正文应该是大写的,但 RESTAPI 返回原始响应(小写)。
httpmodule 最终将用于我无法更改的不同 API。这是我尝试过的一些链接,
- Is it possible to modify the content of HttpRequest POST in an IIS HttpModule?
- How can I modify a POST request using a custom IHttpModule and an HttpRequest filter?
- https://github.com/snives/HttpModuleRewrite/tree/master/HttpModuleRewriteSample
- https://docs.microsoft.com/en-us/dotnet/api/system.web.httprequest.filter?redirectedfrom=MSDN&view=netframework-4.8#System_Web_HttpRequest_Filter
这是HttpModule代码,
using IISWrapper.RequestFilters;
using NLog;
using System;
using System.Web;
using System.Web.SessionState;
namespace IISWrapper {
public class HttpModule : IRequiresSessionState,IHttpModule {
private static readonly Logger log = LogManager.GetCurrentClassLogger();
public HttpModule() { }
public void Init(HttpApplication app) {
app.BeginRequest += OnPostAuthenticateRequest;
}
public void dispose() { }
private void OnPostAuthenticateRequest(object sender,EventArgs args) {
HttpApplication app = (HttpApplication)sender;
app.Context.Request.Filter = new RequestFilter(app.Context.Request.Filter);
}
}
}
using NLog;
using System;
using System.IO;
using System.Runtime.Remoting;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace IISWrapper.RequestFilters {
class RequestFilter : Stream {
private MemoryStream ms;
private Stream _stream;
string content;
byte[] bytes;
//private Encoding _encoding;
private static readonly Logger log = LogManager.GetCurrentClassLogger();
public RequestFilter(Stream stream) {
log.Debug("RequestFilter: Initialise request filter");
_stream = stream;
//_encoding = encoding;
}
public override void Flush() {
log.Debug("Flush:");
ms.Flush();
}
public override long Seek(long offset,SeekOrigin origin) {
log.Debug("Seek:");
return ms.Seek(offset,origin);
}
public override void SetLength(long value) {
log.Debug("SetLength:");
ms.SetLength(value);
}
public override int Read(byte[] buffer,int offset,int count) {
log.Debug($"Read: Content={content}");
if (ms == null) {
log.Debug("Read: Its null:");
var sr = new StreamReader(_stream,Encoding.UTF8);
content = sr.ReadToEnd();
content = content.toupper();
bytes = Encoding.UTF8.GetBytes(content);
ms = new MemoryStream();
ms.Write(bytes,bytes.Length);
ms.Seek(0,SeekOrigin.Begin);
}
log.Debug($"Read: ms.read,content={content}");
log.Debug($"Read: BytesLength={bytes.Length}");
log.Debug($"Read: BufferLength={buffer.Length}");
log.Debug($"Read: BufferToString={Encoding.UTF8.GetString(buffer)}");
log.Debug($"Read: BytesToString={Encoding.UTF8.GetString(bytes)}");
return ms.Read(buffer,offset,count);
}
public override void Write(byte[] buffer,int count) {
log.Debug("Write:");
throw new NotSupportedException();
}
public override bool CanRead {
get {
log.Debug("CanRead:");
return true;
}
}
public override bool CanSeek {
get {
log.Debug("CanSeek:");
return false;
}
}
public override bool CanWrite {
get {
log.Debug("CanWrite:");
return false;
}
}
public override long Length {
get {
log.Debug("Length:");
return ms.Length;
}
}
public override long Position {
get {
log.Debug("Position:");
return ms.Position;
}
set {
throw new NotSupportedException();
}
}
}
}
HttpModule 应用于一个简单的 REST API,它只回显请求,
using log4net;
using System;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Web.Http;
namespace TestRestAPI.Controllers {
public class MyController : ApiController
{
private static readonly ILog log = LogManager.GetLogger(typeof(MyController));
[HttpPost,Route("Echo")]
public HttpResponseMessage Echo() {
try {
log.Debug("Echo: start");
byte[] byteArrayIn = Request.Content.ReadAsByteArrayAsync().Result;
string asstring = Encoding.UTF8.GetString(byteArrayIn);
log.Debug($"Echo: Payload={asstring}");
return Request.CreateResponse(HttpStatusCode.OK,asstring);
} catch (Exception ex) {
log.Error($"Echo: Exception {ex}");
return Request.CreateResponse(HttpStatusCode.OK,ex.ToString());
}
}
}
}
请求正文是“abcdefghijklmnopqrstuvwxyz1234567890”,但来自 RestApi 的响应不是大写的,来自 HttpModule 的日志是,
2021-04-28 16:34:41.3934 [7] DEBUG IISWrapper.RequestFilters.RequestFilter: RequestFilter: Initialise request filter
2021-04-28 16:34:41.6073 [7] DEBUG IISWrapper.RequestFilters.RequestFilter: Read: Content=
2021-04-28 16:34:41.6073 [7] DEBUG IISWrapper.RequestFilters.RequestFilter: Read: Its null:
2021-04-28 16:34:41.6073 [7] DEBUG IISWrapper.RequestFilters.RequestFilter: Read: ms.read,content=ABCDEFGHIJKLMnopQRSUVWXYZ1234567890
2021-04-28 16:34:41.6073 [7] DEBUG IISWrapper.RequestFilters.RequestFilter: Read: BytesLength=35
2021-04-28 16:34:41.6073 [7] DEBUG IISWrapper.RequestFilters.RequestFilter: Read: BufferLength=8192
2021-04-28 16:34:41.6073 [7] DEBUG IISWrapper.RequestFilters.RequestFilter: Read: BufferToString=
2021-04-28 16:34:41.6073 [7] DEBUG IISWrapper.RequestFilters.RequestFilter: Read: BytesToString=ABCDEFGHIJKLMnopQRSUVWXYZ1234567890
2021-04-28 16:34:41.6073 [7] DEBUG IISWrapper.RequestFilters.RequestFilter: Read: Content=ABCDEFGHIJKLMnopQRSUVWXYZ1234567890
2021-04-28 16:34:41.6073 [7] DEBUG IISWrapper.RequestFilters.RequestFilter: Read: ms.read,content=ABCDEFGHIJKLMnopQRSUVWXYZ1234567890
2021-04-28 16:34:41.6073 [7] DEBUG IISWrapper.RequestFilters.RequestFilter: Read: BytesLength=35
2021-04-28 16:34:41.6073 [7] DEBUG IISWrapper.RequestFilters.RequestFilter: Read: BufferLength=8192
2021-04-28 16:34:41.6143 [7] DEBUG IISWrapper.RequestFilters.RequestFilter: Read: BufferToString=ABCDEFGHIJKLMnopQRSUVWXYZ1234567890
2021-04-28 16:34:41.6143 [7] DEBUG IISWrapper.RequestFilters.RequestFilter: Read: BytesToString=ABCDEFGHIJKLMnopQRSUVWXYZ1234567890
这里是rest api的日志,
2021-04-28 16:34:41,603 [7 ] DEBUG TestRestAPI.Controllers.ApiController Echo: start
2021-04-28 16:34:41,615 [7 ] DEBUG TestRestAPI.Controllers.ApiController Echo: Payload=abcdefghijklmnopqrsuvwxyz1234567890
对可能出错的任何建议表示赞赏。
编辑 2021-05-25
我发现要使其工作,端点需要以 .aspx 结尾,并且请求的内容类型必须是“x-www-form-urlencoded”。
问题:
- 有人可以解释为什么它必须是某种内容类型和扩展名吗?
- 是否可以对不以 .aspx 结尾的端点进行这项工作?
编辑 2021-05-27
var _ = context.Request.Form;
触发输入流的评估。然后,如果内容类型为“x-www-form-urlencoded”,则将应用请求过滤器。如果您使用任何其他类型的数据,如 json、xml、原始文本,则请求内容不会因某种原因而改变。也许请求过滤器只适用于表单数据?
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)