asp .net core Get raw request.
小弟初来乍到,分享一些工作学习中遇到的问题和解决方式,如有不准确或是有错误的地方,希望不吝赐教,谢过了。 --dogtwo
背景:
一个代理服务器bk,接收前端a发送的请求,记录log,并转发给另外的服务器b。
请求中有类似这样的模块:
person:
{
name:abc,
age: 20,
address:
{
home: xxx,
company: yyy
}
}
其中home,company以及address为可选字段,服务器b要求如果为空则不传递该字段。
对于前端a来说,如果客户没有填入某字段则json中将不包含该字段。
例如若不包含home,则前端a的request中内容为:
person:
{
name:abc,
age: 20,
address:
{
company: yyy
}
}
前文所述,a的请求会经过bk再转发给b,bk使用asp.netcore,读取a发送来的请求方式如下public task test([frombody] model model)
框架本身已经封装很好,会将request.body中内容自动转化为model对象。对于可选字段home来说,如果前端未发送,
则model.person.address.home的值为""。若请求中address整体都未发送,则model.address为null.
一般来说,这样的处理不会有什么问题。但这次的坑中,我们需要把model再当作内容转发给b,原来使用的方法为(restrequest) request.addjsonbody(model);
此时会使a发送的请求与b接收的请求出现差异!
此时会使a发送的请求与b接收的请求出现差异!
此时会使a发送的请求与b接收的请求出现差异!(重要的事情说三遍)
例如
a发送的:
person:
{
name:abc,
age: 20
}
b接收的:
person:
{
name:abc,
age: 20,
address:null
}
对于基本类型,若某字段可选我们可以这样处理
public int? a { get; set; }
对于内嵌的address来说,经由bk处理后无法取消掉address。(或者是我没找到方法,有办法的话请不吝赐教)
解决办法:
既然框架转化的model不能满足要求,第一思路是直接去取原生的request来获取request.body,转发给b.
但此时在方法为取到的request.body中内容居然为""。明明可以通过[frombody]来获取model,直接取原生内容居然为空,很费解.
网络求助后发现:
asp net core不允许我们仅仅通过方法参数以任何有意义的方式捕获“原始”数据。因此我们需要通过处理request.body来获取原始数据,然后反序列化它。
我们可以捕获原始的request.body并从原始缓冲区中读取参数。最简而有效的方法是接受不带参数的post或put数据,然后从request.body读取原始数据:
例:
1 [httppost("api/blog/jsonstring")] 2 public async task index() 3 { 4 var result = string.empty; 5 6 using (var reader = new streamreader(request.body,encoding.utf8)) 7 { 8 result = await reader.readtoendasync(); 9 } 10 11 return result; 12 }
但在该项目中,使用上述代码取得的result仍为空,笔者代码类似于:
1 [httppost("api/blog/jsonstring")] 2 public async task index([frombody] model model) 3 { 4 var result = string.empty; 5 6 using (var reader = new streamreader(request.body, encoding.utf8)) 7 { 8 result = await reader.readtoendasync(); 9 } 10 11 return result; 12 }
区别在于多了这个[frombody] model model,将其去掉之后result可以成功取得对应值。
继续求助网络发现:
asp.net core 中的 request.body 虽然是一个 stream ,但它是一个与众不同的 stream —— 不允许 request.body.position=0
,这就意味着只能读取一次。
解决办法为
引用命名空间 microsoft.aspnetcore.http.internal
,调用方法 request.enablerewind()
(但尝试时该方法无效,需要进一步研究)
另外,成功取得request.body值以后要用这个方法将其加入到新的request中:request.addparameter("application/json", result, parametertype.requestbody)
;
参考:
1. asp.net core web api获取原始请求内容
2. asp.net core 中读取 request.body 的正确姿势
3.returning only useful fields from the api && consuming an api that accepts a comma-separated list of fields.
上一篇: 以太网口和串口在查看端口状态时的区别
下一篇: 你要什么光
推荐阅读
-
ASP.NET Core MVC/API(一)
-
Asp.Net Core MVC项目实现多语言实例(Globalization/Localization)
-
Amazing ASP.NET Core 2.0
-
ASP.NET Core优雅的在开发环境保存机密(User Secrets)
-
asp.net core 自定义 Policy 替换 AllowAnonymous 的行为
-
ASP.NET Core API总结(一)
-
asp.net core分块上传文件示例
-
详解ASP.NET与ASP.NET Core用户验证Cookie并存解决方案
-
ASP.NET Core中使用默认MVC路由的配置
-
asp.net core IdentityServer4 实现 resource owner password credentials(密码凭证)