zoukankan      html  css  js  c++  java
  • 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.

  • 相关阅读:
    AT2172 Shik and Travel
    bzoj5138 [Usaco2017 Dec]Push a Box
    bzoj3545 [ONTAK2010]Peaks、bzoj3551 [ONTAK2010]Peaks加强版
    bzoj5183 [Baltic2016]Park
    bzoj4423 [AMPPZ2013]Bytehattan
    bzoj2125 最短路
    斐波那契数列小结
    记一场模拟赛
    洛谷2387 BZOJ3669魔法森林题解
    COGS-2638 区间与,异或,询问max
  • 原文地址:https://www.cnblogs.com/dogtwo0214/p/10177403.html
Copyright © 2011-2022 走看看