asp.net core 实现支持自定义 Content-Type

Intro

我们最近有一个原本是内网的服务要上公网,在公网上有一层 Cloudflare 作为网站的公网流量提供者,CloudFlare 会有一层防火墙拦截掉一些非法的请求,我们有一些 API 会提交一些 html 内容,经过 Cloudflare 的时候会被 Cloudflare 拦截,导致某些功能不能够正常使用,于是就想对提交的数据进行一个编码之后再提交,服务器端针对需要解码的请求进行解码再解析,我们新加了一个 Content-Type 的支持,编码后的数据使用新的 Content-Type,对于不编码的数据依然可以工作,目前我们做了一个简单的 base64 编码,如果需要的话也可以实现复杂一些的加密、压缩等。

Basis

asp.net core 默认支持 JSON 请求,因为内置了针对 JSON 内容的 Formatter,.NET Core 2.x 使用的是 Newtonsoft.Json 作为默认 JSON formatter,从 .NET Core 3.0 开始引入了 System.Text.Json 作为默认的 JSON formatter,如果要支持 XML 需要引入针对 XML 的 formatter,相应的如果需要增加其他类型的请求实现自己的 formatter 就可以了

Formatter 分为 InputFormatterOutputFormatter

  • InputFormatter 用来解析请求 Body 的数据,将请求参数映射到强类型的 model,Request Body => Value

  • OutputFormatter 用来将强类型的数据序列化成响应输出,Value => Response Body

Formatter 需要指定支持的 MediaType,可以理解为请求类型,体现在请求头上,对于 InputFormatter 对应的就是  Content-Type ,对于 OutputFormatter 对应的是 Accept,asp.net core 会根据请求信息来选择注册的 formatter。

Sample

先来看一下实现效果吧,实现效果如下:

swagger

swagger 的支持也算比较好了,在增加了新的 Content-Type 支持之后在 swagger 上可以看得到,而且可以切换请求的 Content-Type,上图中的 text/base64-json 就是我自定义的一个 Content-Type

默认请求:

json-request

对原始请求进行 base64 编码,再请求:

base64-json-request

Implement

实现代码如下:

public class Base64EncodedJsonInputFormatter : TextInputFormatter
{public Base64EncodedJsonInputFormatter(){// 注册支持的 Content-TypeSupportedMediaTypes.Add("text/base64-json");SupportedEncodings.Add(Encoding.UTF8);}public override async Task<InputFormatterResult> ReadRequestBodyAsync(InputFormatterContext context, Encoding encoding){try{using var reader = context.ReaderFactory(context.HttpContext.Request.Body, encoding);var rawContent = await reader.ReadToEndAsync();if (string.IsNullOrEmpty(rawContent)){return await InputFormatterResult.NoValueAsync();}var bytes = Convert.FromBase64String(rawContent);var services = context.HttpContext.RequestServices;var modelValue = await GetModelValue(services, bytes);return await InputFormatterResult.SuccessAsync(modelValue);async ValueTask<object> GetModelValue(IServiceProvider serviceProvider, byte[] stringBytes){var newtonJsonOption = serviceProvider.GetService<IOptions<MvcNewtonsoftJsonOptions>>()?.Value;if (newtonJsonOption is null){await using var stream = new MemoryStream(stringBytes);var result = await System.Text.Json.JsonSerializer.DeserializeAsync(stream, context.ModelType,services.GetRequiredService<IOptions<JsonOptions>>().Value.JsonSerializerOptions);return result;}var stringContent = encoding.GetString(bytes);return Newtonsoft.Json.JsonConvert.DeserializeObject(stringContent, context.ModelType, newtonJsonOption.SerializerSettings);}}catch (Exception e){context.ModelState.TryAddModelError(string.Empty, e.Message);return await InputFormatterResult.FailureAsync();}}
}

上述代码兼容了使用 System.Text.JsonNewtonsoft.Json,在发生异常时将错误信息添加一个 ModelError 以便在前端可以得到错误信息的反馈,例如传一个不合法的 base64 字符串就会像下面这样:

error

实际使用的时候,只需要在 Startup 里配置一下就可以了,如:

services.AddControllers(options =>{options.InputFormatters.Add(new Base64EncodedJsonInputFormatter());});

More

通过自定义 Content-Type 的支持我们可以无侵入的实现不同的请求内容,上面的示例代码可以在 Github 上获取 https://github.com/WeihanLi/SamplesInPractice/tree/master/AspNetCoreSample,可以根据自己的需要进行自定义

References

  • https://docs.microsoft.com/en-us/aspnet/core/web-api/advanced/custom-formatters?view=aspnetcore-5.0

  • https://github.com/dotnet/AspNetCore.Docs/tree/main/aspnetcore/web-api/advanced/custom-formatters/samples

  • https://github.com/WeihanLi/SamplesInPractice/tree/master/AspNetCoreSample

asp.net core 自定义 Content-Type相关推荐

  1. asp.net core 自定义基于 HttpContext 的 Serilog Enricher

    asp.net core 自定义基于 HttpContext 的 Serilog Enricher Intro 通过 HttpContext 我们可以拿到很多有用的信息,比如 Path/QuerySt ...

  2. asp.net core 自定义 Policy 替换 AllowAnonymous 的行为

    asp.net core 自定义 Policy 替换 AllowAnonymous 的行为 Intro 最近对我们的服务进行了改造,原本内部服务在内部可以匿名调用,现在增加了限制,通过 identit ...

  3. ASP.NET Core 改变 content 和 web root(wwwroot) 目录路径

    ASP.NET Core 改变 content 和 web root 根目录路径 先说方法: 方法一: 添加环境变量 ASPNETCORE_CONTENTROOT 与 ASPNETCORE_WEBRO ...

  4. 解决 ASP.NET Core 自定义错误页面对 Middleware 异常无效的问题

    我们基于 Razor Class Library 实现了自定义错误页面的公用类库(详见之前的随笔),但是在实际使用时发现如果在 middleware 中发生了异常,则不能显示自定义错误页面,而是返回默 ...

  5. asp.net core自定义依赖注入容器,替换自带容器

    依赖注入 在asp.net core程序中,众所周知,依赖注入基本上贯穿了整个项目,以通用的结构来讲解,控制器层(Controller层)依赖业务层(Service层),业务层依赖于仓储层(Repos ...

  6. asp.net core 自定义401和异常显示内容(JWT认证、Cookie Base认证失败显示内容)

    asp.net core 2.0使用JWT认证园子里已经有挺多帖子了,但开发中发现认证未授权情况下返回的401状态码是没有任何信息的,业务中可能有需要返回一串错误的Json信息.在这里我分享一个自定义 ...

  7. ASP.NET Core自定义响应内容

    问题 在业务开发中,对Web API的返回格式有一定要求,需要是定制化的Json结构,用于前端统一处理: {Status : 0,Message: "",Info : xxx } ...

  8. asp.net core 自定义异常处理中间件

    Intro 在 asp.net core 中全局异常处理,有时候可能不能满足我们的需要,可能就需要自己自定义一个中间件处理了,最近遇到一个问题,有一些异常,不希望记录错误日志,目前主要是用户请求取消导 ...

  9. ASP.NET Core 自定义认证方式--请求头认证

    Intro 最近开始真正的实践了一些网关的东西,最近写几篇文章分享一下我的实践以及遇到的问题. 本文主要介绍网关后面的服务如何进行认证. 解决思路 网关可以做一部分的认证和授权,服务内部有时候也会需要 ...

最新文章

  1. Goldman Sachs 2020校招 Engineer岗
  2. 1.httpClient和ScrollView
  3. C#调用vbs脚本实现Windows版Siri
  4. [react] 为什么建议setState的第一个参数是callback而不是一个对象呢?
  5. 使用data()方法缓存数据
  6. 设置和开通freebsd远程登录
  7. openstack horizon dashboard_OpenStack最新版本:Ussuri发布亮点
  8. 如何在恢复模式下启动 Mac?
  9. Elasticsearch5.x 升级
  10. 自建服务器选择标准,自建CDN如何选择服务器
  11. 亲测可用sqlyog激活注册码
  12. ubuntuv20启动界面美化_小米任务栏美化软件下载-小米任务栏美化官方版软件下载v1.0...
  13. 计算机网络-3-局域网数据链路层原理与技术
  14. appfuse mysql_AppFuse 2.1的安装运行步骤
  15. 段码超低功耗LCD液晶显示驱动芯片(IC)-VKL系列-VKL128/060/076/144A/144B,VKL144A兼容MCP144
  16. 月入万元或不需缴税!九张图带你看懂个税新规
  17. 过滤:sql、敏感词、html、js、css
  18. postgresql常用命令和执行sql脚本
  19. 创建自己的ERC20加密货币(可管理、增发、兑换、冻结等高级功能的代币)
  20. 遥感数据下载——FIRM:VIIRS火点数据、MODIS火点数据简介及下载

热门文章

  1. QCustomplot(一) 能做什么事
  2. ubuntu linux下建立stm32开发环境: 程序烧录 openocd+openjtag
  3. 数据库_7_SQL基本操作——表操作
  4. Java 打飞机(小游戏)[版权非本人 本人制作收藏整理]
  5. HTTPS协议开通,Apache服务器CSR签名申请
  6. 社交网络图中结点的“重要性“计算(Dijkstra + SPFA + Floyd + 模板)
  7. BFS HDOJ 2102 A计划
  8. NOI导刊模拟2—电话网络 解题报告
  9. android 设备名称_如何更改您的Android TV的设备名称
  10. 学习韩立刚老师IT运维课程,成为韩立刚老师正式学生,在全国范围为你就近推荐工作。...