ASP.NET Core-中间件中读取、修改Request.Body、Response.Body

修改Request.Body

//这里ReadToEnd执行完毕后requestBodyStream流的位置会从0到最后位置(即request.ContentLength)            
            var RequestBody = new StreamReader(HttpContext.Request.BodyReader.AsStream()).ReadToEnd();//读取body
            byte[] content1 = Encoding.UTF8.GetBytes(RequestBody.Replace("ceo", "CEO"));//替换字符串并且字符串转换成字节

            var requestBodyStream = new MemoryStream();//创建一个流 
            requestBodyStream.Seek(0, SeekOrigin.Begin);//设置从0开始读取
            requestBodyStream.Write(content1, 0, content1.Length);//把修改写入流中
            HttpContext.Request.Body = requestBodyStream;//把修改后的内容赋值给请求body
            HttpContext.Request.Body.Seek(0, SeekOrigin.Begin);

同步读取(不推荐)

如果需要同步读取Requestbody,需要在读取之前做如下设置,否则报错

  • 方式1:
services.Configure<KestrelServerOptions>(options =>
{
    options.AllowSynchronousIO = true;
});
  • 方式2:读取RequestBody之前设置IHttpBodyControlFeature.AllowSynchronousIO
var syncIOFeature = base.HttpContext.Features.Get<IHttpBodyControlFeature>();
if (syncIOFeature != null)
{
    syncIOFeature.AllowSynchronousIO = true;
}

StreamReader stream = new StreamReader(base.Request.Body);
string body = stream.ReadToEnd();//同步读取
_logger.LogDebug("body content:" + body);

多次读取Body

如果需要多次读取Body,操作RequestBody之前加上Request.EnableBuffering()即可

base.Request.EnableBuffering();

StreamReader stream = new StreamReader(base.Request.Body);
string body = await stream.ReadToEndAsync();
_logger.LogDebug("body content:" + body);

base.Request.Body.Seek(0, SeekOrigin.Begin);
StreamReader stream2 = new StreamReader(base.Request.Body);
string body2 = await stream2.ReadToEndAsync();
base.Request.Body.Seek(0, SeekOrigin.Begin);
_logger.LogDebug("body2 content:" + body2);

修改Response.Body

默认的ResponseStream不能读和写操作,更换默认的ResponseStream为MemoryStream,这样就可以对Response输出的内容进行读写操作了

public class ResponseDistributedCacheMiddleware
    {
        protected RequestDelegate _next;

        private ILogger<ResponseDistributedCacheMiddleware> _logger;

        public ResponseDistributedCacheMiddleware(RequestDelegate next, ILogger<ResponseDistributedCacheMiddleware> logger)
        {
            this._next = next;
            this._logger = logger;
        }

        public async Task Invoke(HttpContext httpContext)
        {
#if DEBUG
            #region request
            string bodyAsText = null;
            HttpRequest request = httpContext.Request;
            string method = request.Method;

            if (HttpMethods.IsPost(method)  //新增
             || HttpMethods.IsPut(method)   //修改全部
             || HttpMethods.IsPatch(method) //修改部分
            )
            {
                //https://devblogs.microsoft.com/aspnet/re-reading-asp-net-core-request-bodies-with-enablebuffering/
                request.EnableBuffering();//允许多次读取HTTP请求的正文
                using (var reader = new StreamReader(request.Body,
                                                     encoding: Encoding.UTF8,
                                                     detectEncodingFromByteOrderMarks: false,
                                                     leaveOpen: true)
                      )
                {
                    bodyAsText = await reader.ReadToEndAsync();
                    request.Body.Position = 0;
                }
                if (!string.IsNullOrWhiteSpace(bodyAsText))
                {
                    bodyAsText = System.Web.HttpUtility.UrlDecode(bodyAsText);
                }
            }
            #endregion
#endif
            #region response
            HttpResponse response = httpContext.Response;
            var responseOriginalStream = response.Body;
            try
            {
                using (var memoryResponseStream = new MemoryStream())
                {
                    //更换默认的Response流对象
                    response.Body = memoryResponseStream;
                    await _next.Invoke(httpContext);
                    memoryResponseStream.Seek(0, SeekOrigin.Begin);
                    await memoryResponseStream.CopyToAsync(responseOriginalStream);
                }
            }
            catch (Exception e)
            {
                this._logger.LogError(e, "出错啦(┬_┬)");
            }
            finally
            {
                response.Body = responseOriginalStream;
            }
            #endregion

        }

    }

参考:
https://www.cnblogs.com/wucy/p/14699717.html
https://www.cnblogs.com/lwqlun/p/10954936.html
https://zablo.net/blog/post/asp-net-core-redis-html-cache/ (缓存)

posted @ 2020-02-21 15:59  .Neterr  阅读(4058)  评论(0编辑  收藏  举报