在Asp.net Core控制器中,通过自定义格式化程序来映射自定义处理控制器中的“未知”内容。

简单案例

为了演示这个问题,我们用VS2017创建一个默认的Asp.net Core Web Api项目。

    [Route("api/[controller]")][ApiController]public class ValuesController : ControllerBase{[HttpGet]public ActionResult<string> Get() {return "ok";}[HttpPost][Route("PostX")]public ActionResult<string> Post([FromBody] string value){return value;}}

Json请求

我们从最常见的json输入请求开始。

User-Agent: Fiddler
Host: localhost:5000
Content-Type: application/json
Content-Length: 16

请求body:

{"123456"}

通过后台调试和fiddler抓包,我们可以看到请求输入和返回。

后台调试,查看请求输入结果

fiddler查看请求header

fiddler查看返回结果

注意!!

  • 别忘了[FromBody],有时候会忘的。
  • 后台action接收类型为string的时候,请求body只能是字符串,不能传json对象。我演示这个例子时,被这点坑了。如果接收对象是一个类的时候,才可以传json对象。

没有JSON

虽然传输json数据是最常用的,但有时候我们需要支持普通的文本或者二进制信息。我们将Content-Type改为
text/plain

User-Agent: Fiddler
Host: localhost:5000
Content-Type:text/plain
Content-Length: 16

请求body:

{"123456"}

悲剧的事情来,报404!

不支持text/plain

事情到此就变得稍微复杂了一些,因为asp.netcore只处理它认识的类型,如json和formdata。默认情况下,原始数据不能直接映射到控制器参数。这是个小坑,不知你踩到过没有?仔细想想,这是有道理的。MVC具有特定内容类型的映射,如果您传递的数据不符合这些内容类型,则无法转换数据,因此它假定没有匹配的端点可以处理请求。
那么怎么支持原始的请求映射呢?

支持原始正文请求

不幸的是,ASP.NET Core不允许您仅通过方法参数以任何有意义的方式捕获“原始”数据。无论如何,您需要对其进行一些自定义处理Request.Body以获取原始数据,然后对其进行反序列化。

您可以捕获原始数据Request.Body并从中直接读取原始缓冲区。

最简单,最不易侵入,但不那么明显的方法是使用一个方法接受没有参数的 POST或PUT数据,然后从Request.Body以下位置读取原始数据:

读取字符串缓冲区

        [HttpPost][Route("PostText")]public async Task<string> PostText(){using (StreamReader reader = new StreamReader(Request.Body, Encoding.UTF8)){return await reader.ReadToEndAsync();}}

这适用于一下Http和文本

User-Agent: Fiddler
Host: localhost:5000
Content-Type: text/plain
Content-Length: 6

要读取二进制数据,你可以使用以下内容:

读取byte缓冲区

        [HttpPost][Route("PostBinary")]public async Task<byte[]> PostBinary(){using (var ms = new MemoryStream(2048)){await Request.Body.CopyToAsync(ms);return ms.ToArray();  // returns base64 encoded string JSON result}}

查看执行结果

接收文本内容

接收二进制数据

HttpRequest静态扩展

如果你为了方便,写了很多HttpRequest的扩展,接收参数时,可以看起来更简洁一些。

public static class HttpRequestExtension{/// <summary>/// /// </summary>/// <param name="httpRequest"></param>/// <param name="encoding"></param>/// <returns></returns>public static async Task<string> GetRawBodyStringFormater(this HttpRequest httpRequest, Encoding encoding){if (encoding == null){encoding = Encoding.UTF8;}using (StreamReader reader = new StreamReader(httpRequest.Body, encoding)){return await reader.ReadToEndAsync();}}/// <summary>/// 二进制/// </summary>/// <param name="httpRequest"></param>/// <param name="encoding"></param>/// <returns></returns>public static async Task<byte[]> GetRawBodyBinaryFormater(this HttpRequest httpRequest, Encoding encoding){if (encoding == null){encoding = Encoding.UTF8;}using (StreamReader reader = new StreamReader(httpRequest.Body, encoding)){using (var ms = new MemoryStream(2048)){await httpRequest.Body.CopyToAsync(ms);return ms.ToArray();  // returns base64 encoded string JSON result}}}}
        [HttpPost][Route("PostTextX")]public async Task<string> PostTextX(){return await Request.GetRawBodyStringAsyn();}/// <summary>/// 接收/// </summary>/// <returns></returns>[HttpPost][Route("PostBinaryX")]public async Task<byte[]> PostBinaryX(){return await Request.GetRawBodyBinaryAsyn();}

自动转换文本和二进制值

上面虽然解决了原始参数转换问题,但不够友好。如果你打算像原生MVC那样自动映射参数的话,你需要做一些自定义格式化适配。

创建一个Asp.net MVC InputFormatter

ASP.NET Core使用一种干净且更通用的方式来处理内容的自定义格式InputFormatter。输入格式化程序挂钩到请求处理管道,让您查看特定类型的内容以确定是否要处理它。然后,您可以阅读请求正文并对入站内容执行自己的反序列化。
InputFormatter有几个要求

  • 您需要使用[FromBody]去获取
  • 您必须能够查看请求并确定是否以及如何处理内容。

在这个例子中,对于“原始内容”,我想查看具有以下类型的请求:

  • text/plain(文本)
  • appliaction/octet-stream(byte[])
    没有内容类型(string)

要创建格式化程序,你可以实现IInputFormatter或者从InputFormatter继承。

    public class RawRequestBodyFormatter : IInputFormatter{public RawRequestBodyFormatter(){}public bool CanRead(InputFormatterContext context){if (context == null) throw new ArgumentNullException("argument is Null");var contentType = context.HttpContext.Request.ContentType;if (string.IsNullOrEmpty(contentType) || contentType == "text/plain" || contentType == "application/octet-stream")return true;return false;}public async Task<InputFormatterResult> ReadAsync(InputFormatterContext context){var request = context.HttpContext.Request;var contentType = context.HttpContext.Request.ContentType;if (string.IsNullOrEmpty(contentType) || contentType.ToLower() == "text/plain"){using (StreamReader reader = new StreamReader(request.Body, Encoding.UTF8)){var content = await reader.ReadToEndAsync();return await InputFormatterResult.SuccessAsync(content);}}if (contentType == "application/octet-stream"){using (StreamReader reader = new StreamReader(request.Body, Encoding.UTF8)){using (var ms = new MemoryStream(2048)){await request.Body.CopyToAsync(ms);var content = ms.ToArray();return await InputFormatterResult.SuccessAsync(content);}}}return await InputFormatterResult.FailureAsync();}}

格式化程序用于CanRead()检查对内容类型的请求以支持,然后将ReadRequestBodyAsync()内容读取和反序列化为应在控制器方法的参数中返回的结果类型。

InputFormatter必须在ConfigureServices()启动代码中注册MVC :

 public void ConfigureServices(IServiceCollection services){services.AddMvc(o=>o.InputFormatters.Insert(0,new RawRequestBodyFormatter())).SetCompatibilityVersion(CompatibilityVersion.Version_2_1);}

接受原始输入

        [HttpPost][Route("PostTextPlus")]public string PostTextPlus([FromBody] string value){return value;}

然后你就可以发送post请求,像这样:

User-Agent: Fiddler
Host: localhost:5000
Content-Length: 6

或者

User-Agent: Fiddler
Host: localhost:5000
Content-Type:text/plain
Content-Length: 6

请注意,您可以使用内容类型调用相同的控制器方法application/json并传递JSON字符串,这也将起作用。在RawRequestBodyFormatter 简单地增加它支持的附加内容类型的支持。

二进制数据

        [HttpPost][Route("PostBinaryPlus")]public byte[] PostBinaryPlus([FromBody] byte[] value){return value;}

请求内容如下:

User-Agent: Fiddler
Host: localhost:5000
Content-Length: 6
Content-Type: application/octet-stream

源代码

示例代码已上传到 CsharpFanDemo

参考链接

本文包含翻译和自己实践。主要思路和代码来源于以下链接:
Accepting Raw Request Body Content in ASP.NET Core API Controllers

转自:https://www.cnblogs.com/fancunwei/p/9567497.html

http post Raw(application/json)数据接收处理相关推荐

  1. layui 传递前端请求_Layui数据表格 前后端json数据接收的方法

    先上效果图: 前端数据表格: 编号菜单名称菜单路径菜单图标菜单子菜单操作 编辑 删除 js代码 $(function () { //注意:这里是数据表格的加载数据,必须写 layui.use(['ta ...

  2. struts的json数据接收解析

    json格式 /*** 类描述:接收json数据修改延期时间** @ClassName BankManageMent* @Description TODO* @Author 张 * @Date * @ ...

  3. libcurl Get json 数据 接收全部的数据

    默认情况下 , 回调里面会将数据分段的返回,不会一下子将发送端的数据全部塞到回调函数里面 解决方法: 大家可以看到其实回调函数和curl_easy_perform是在一个线程里面的,所以我们可以在回调 ...

  4. Layui(1) 数据表格 前后端json数据接收

    先上效果图: 前端数据表格: <div class="x-body"><%-- 数据表格 --%><table class="layui-t ...

  5. [转载] application/json 四种常见的 POST 提交数据方式

    参考链接: 关于/联系我 application/json 四种常见的 POST 提交数据方式 转载声明: 本文系转载自以下两篇文章: 四种常见的 POST 提交数据方式 作者: 沧海一滴 转载仅为方 ...

  6. 请求头Content-Type:application/json,java后端如何接收数据

    Content-Type的类型 1.application/x-www-form-urlencoded ​ 常用@RequestParam("参数名称")也可以不写使用spring ...

  7. Content-Type为application/json后台如何接收前台数据

    Content-Type为application/json时,假设前台传输的数据为data: {name:'wyc',age:12} 第一种情况在springmvc框架下 处理方法为前台post请求, ...

  8. Controller接收处理json数据

    Controller如何处理json数据 1.使用RequestBody接收json数据,并转换为对象 封装的Permission对象,用于接收json数据. @Data @Data public c ...

  9. 解决SpringMvc后台接收json数据中文乱码问题

    2019独角兽企业重金招聘Python工程师标准>>> 1.使用ajax从前台页面传输数据到后台controller控制器的时候,出现中文乱码(问号???). 之前在网上找了各种解决 ...

最新文章

  1. 经典面试题:计算积水的横截面积
  2. Mybatis中的缓存
  3. 【linux】Shell脚本中调用另外一个脚本的方法
  4. MySQL高级 - InnoDB特性
  5. antlr_ANTLR –语义谓词
  6. python3 整除_python如何整除
  7. vue element序号翻页连续排序
  8. 使用 JQuery EasyUI
  9. 操作系统 读者-写者问题
  10. 综述---图像处理中的注意力机制
  11. 实用供暖通风空调设计手册 第三版_实用供热空调设计手册第三版即将出版随想...
  12. 手Q与微信:最终结局将会是手足相残!
  13. 什么叫做项目孵化_什么是创业孵化园,孵化基地的五大要素有哪些?
  14. filter_var函数缺陷(原理+实践)
  15. 如何构建用户画像来实现精准营销?
  16. C语言 投票系统:给定候选人,从键盘输入候选人的名字,统计票数,并输出最终获胜者...
  17. 常用元器件使用方法1:DCDC降压芯片SY8303的使用方法
  18. Chapter5 生长因子、受体和癌症
  19. CocoaChina 允许iOS开发者相互推广自己的作品,发码大师相当不错!
  20. 手把手教你使用HFSS仿真高速差分过孔—上

热门文章

  1. 修改注册表设置管理员权限
  2. STM32MP157 | 虚拟网卡设备驱动
  3. 陌陌android4.4,陌陌4.4版本上线
  4. Halcon单相机标定—标定板标定和自标定 线扫相机标定
  5. VMware共享文件夹
  6. excel数据按某列分类并新建sheet类工作表
  7. “数”造城市 “智”造未来
  8. 解决Java线程死锁问题及代码实例
  9. 万能DOS启动盘制作全攻略!(软盘+光盘+U盘+硬盘+NTFS+应急实用工具)
  10. 如何运用项目思维制订店年度经营目标?