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/ (缓存)