修改 HttpModule 中的请求正文

问题描述

我正在尝试编写一个 HttpModule,它会在请求正文到达 RestAPI 之前更改它。目标是在内容类型为“x-www-form-urlencoded”的请求正文中添加一些键值。我的第一次尝试是仅将有效负载中的字符更改为大写。为了测试这一点,将 httpmodule 添加一个简单的 restapi 中,它在响应中返回请求内容。 httpmodule 的日志显示请求正文应该是大写的,但 RESTAPI 返回原始响应(小写)。

httpmodule 最终将用于我无法更改的不同 API。这是我尝试过的一些链接

这是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 (将#修改为@)

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...