Web API Request Content多次读取
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Web API Request Content多次读取相关的知识,希望对你有一定的参考价值。
使用OWIN
项目中要做日志过滤器
新建类ApiLogAttribute
继承ActionFilterAttribute
ApiLogAttribute : ActionFilterAttribute
public override Task OnActionExecutingAsync(HttpActionContext actionContext, CancellationToken cancellationToken) { string result = null; Stream stream = actionContext?.Request?.Content?.ReadAsStreamAsync().Result; stream.Position = 0L; Encoding encoding = Encoding.UTF8; /* 这个StreamReader不能关闭,也不能dispose, 关了就傻逼了 因为你关掉后,后面的管道 或拦截器就没办法读取了 */ var reader = new StreamReader(stream, encoding); result = reader.ReadToEnd(); /* 这里也要注意: stream.Position = 0; 当你读取完之后必须把stream的位置设为开始 因为request和response读取完以后Position到最后一个位置,交给下一个方法处理的时候就会读不到内容了。 */ stream.Position = 0L; Console.WriteLine(result); return base.OnActionExecutingAsync(actionContext, cancellationToken); }
结果发现stream Position 无法设置,CanSeek为false
用 流复制也不管用
MemoryStream stream = new MemoryStream();
Stream.CopyToAsync(stream);
始终读取不到内容
最后读取文档得知 OWIN 中 Request 的content 只能读取一次,已经被解析,无法再次读取
百度 谷歌了一番
https://stackoverflow.com/questions/31389781/read-request-body-twice/31395692#31395692
解决办法如下
在Startup中添加添加中间件
这里的流还没有被读取过,直接复制一份CanSeek为false的stream 流 ,进行替换
//Request stream重用 app.Use(async (context, next) => { // Keep the original stream in a separate // variable to restore it later if necessary. var stream = context.Request.Body; // Optimization: don‘t buffer the request if // there was no stream or if it is rewindable. if (stream == Stream.Null || stream.CanSeek) { await next.Invoke(); return; } try { using (var buffer = new MemoryStream()) { // Copy the request stream to the memory stream. await stream.CopyToAsync(buffer); // Rewind the memory stream. buffer.Position = 0L; // Replace the request stream by the memory stream. context.Request.Body = buffer; // Invoke the rest of the pipeline. await next.Invoke(); } } finally { // Restore the original stream. context.Request.Body = stream; } });
或者 在过滤器中 通过如下放法 直接 取出已经被解析的参数
/// <summary> /// 读取request 的提交内容 /// </summary> /// <param name="actionContext"></param> /// <returns></returns> public string GetRequestValues(HttpActionContext actionContext) { string result = null; foreach (var arg in actionContext.ActionArguments) { if (arg.Value == null) continue; var type = arg.Value.GetType(); if (type == typeof(HttpRequestMessage)) { result += $"key={arg.Key};"; var bytes = ((HttpRequestMessage)arg.Value).Content.ReadAsByteArrayAsync().Result; var decode = HttpUtility.UrlDecode(bytes, 0, bytes.Length, Encoding.GetEncoding("GBK")); result += $"value={decode};{Environment.NewLine}"; } else { result += $"key={arg.Key};"; result += $"value={JsonConvert.SerializeObject(arg.Value)};{Environment.NewLine}"; } } return result; }
以上是关于Web API Request Content多次读取的主要内容,如果未能解决你的问题,请参考以下文章
Method not found: then send request web api controller
asp.net core 3.0 web api request.body和[frombody]冲突[关闭]
使用HttpContext.Current.Request.Form Web API后的404 POST状态
C# EF6 使用 Unity 对一个上下文进行多次异步调用 - Asp.Net Web Api
ASP.NET Web Api HttpResponseException 400 (Bad Request) 被 IIS 劫持