asp.net core 实现支持自定义 Content-Type
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 分为 InputFormatter 和 OutputFormatter
InputFormatter用来解析请求Body的数据,将请求参数映射到强类型的 model,Request Body => ValueOutputFormatter用来将强类型的数据序列化成响应输出,Value => Response Body
Formatter 需要指定支持的 MediaType,可以理解为请求类型,体现在请求头上,对于 InputFormatter 对应的就是 Content-Type ,对于 OutputFormatter 对应的是 Accept,asp.net core 会根据请求信息来选择注册的 formatter。
Sample
先来看一下实现效果吧,实现效果如下:

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

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

Implement
实现代码如下:
public class Base64EncodedJsonInputFormatter : TextInputFormatter
{
public Base64EncodedJsonInputFormatter()
{
// 注册支持的 Content-Type
SupportedMediaTypes.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.Json 和 Newtonsoft.Json,在发生异常时将错误信息添加一个 ModelError 以便在前端可以得到错误信息的反馈,例如传一个不合法的 base64 字符串就会像下面这样:

实际使用的时候,只需要在 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的更多相关文章
- WebAPI调用笔记 ASP.NET CORE 学习之自定义异常处理 MySQL数据库查询优化建议 .NET操作XML文件之泛型集合的序列化与反序列化 Asp.Net Core 轻松学-多线程之Task快速上手 Asp.Net Core 轻松学-多线程之Task(补充)
WebAPI调用笔记 前言 即时通信项目中初次调用OA接口遇到了一些问题,因为本人从业后几乎一直做CS端项目,一个简单的WebAPI调用居然浪费了不少时间,特此记录. 接口描述 首先说明一下,基于 ...
- Asp.Net Core入门之自定义服务注册
谈到服务注册,首先我们先了解一下服务注册时使用的三种方式,也代表了不同的服务生命周期: AddTransient AddScoped AddSingleton AddSingleton生命周期最长,其 ...
- asp.net core 3.1 自定义中间件实现jwt token认证
asp.net core 3.1 自定义中间件实现jwt token认证 话不多讲,也不知道咋讲!直接上代码 认证信息承载对象[user] /// <summary> /// 认证用户信息 ...
- asp.net core 实现支持多语言
asp.net core 实现支持多语言 Intro 最近有一个外国友人通过邮件联系我,想用我的活动室预约,但是还没支持多语言,基本上都是写死的中文,所以最近想支持一下更多语言,于是有了多语言方面的一 ...
- ASP.NET Core中显示自定义错误页面-增强版
之前的博文 ASP.NET Core中显示自定义错误页面 中的方法是在项目中硬编码实现的,当有多个项目时,就会造成不同项目之间的重复代码,不可取. 在这篇博文中改用middleware实现,并且放在独 ...
- 使Asp.net Core同时支持输出Json/Xml
我们知道Asp.net Core是支持输出为Json格式的.同时也支持输出为xml格式.只要我们正确的配置.并在Request时指定正确的Accept,即可根据不同的Header来输出不同的格式. 前 ...
- ASP.NET Core中使用自定义路由
上一篇文章<ASP.NET Core中使用默认MVC路由>提到了如何使用默认的MVC路由配置,通过这个配置,我们就可以把请求路由到Controller和Action,通常情况下我们使用默认 ...
- 在ASP.NET Core中创建自定义端点可视化图
在上篇文章中,我为构建自定义端点可视化图奠定了基础,正如我在第一篇文章中展示的那样.该图显示了端点路由的不同部分:文字值,参数,动词约束和产生结果的端点: 在本文中,我将展示如何通过创建一个自定义的D ...
- ASP.NET Core - 实现Http自定义请求头策略
前言 在正常的情况下,当我们系统用到JWT认证方式时,需要在Http请求头添加Authorization: XXX,这样在后台服务的控制器中打上[Authorize]授权标签,就限定所有的请求必须通过 ...
随机推荐
- Nginx 版本回滚
目录 参考信息 源码安装 nginx-1.14.2 版本升级 nginx-1.16.1 版本回滚 ①.对于软件的版本升级.添加官方模块.添加第三方模块,都需要用源码安装包重新生成(configure) ...
- Linux-文件查看命令
目录 系统文件查看命令-cat 系统文件查看命令-more 系统文件查看命令-less 系统文件查看命令-head 系统文件查看命令-tail 系统文件查看命令-grep 文件上传下载命令-rz,sz ...
- Kubernets二进制安装(14)之flannel之SNAT规则优化
flannel之SNAT规则优化的目的是由于在K8S中的容器内,访问不同宿主机中的容器的资源的时候,日志文件会记录为宿主机的IP地址,而不是记录为容器本身自己的IP地址,建议在不同的宿主机上的容器互访 ...
- python 3.7 安装 sklearn keras(tf.keras)
# 1 sklearn 一般方法 网上有很多教程,不再赘述. 注意顺序是 numpy+mkl ,然后 scipy的环境,scipy,然后 sklearn # 2 anoconda ana ...
- Pymongo 笔记
Pymongo 1.MongoDB概念 MongoDB是一种非关系型数据库(NoSQL),MongoDB数据存储于内存,内存不足则将热度低数据写回磁盘.存储的数据结构为文档.每个数据库包含若干集合(c ...
- Vue dynamic component All In One
Vue dynamic component All In One Vue 动态组件 vue 2.x https://vuejs.org/v2/guide/components-dynamic-asyn ...
- PyCharm 中文 字符 python 报错 的 完美 解决方案!
PyCharm 中文 字符 python 报错 的 完美 解决方案! #_*_ coding:utf-8_*_ https://www.python.org/dev/peps/pep-0263/ 到p ...
- 如何理解NGK的Layer2-侧链?
对于 NGK来说,Layer-2越来越重要,并成为共识.但是,"Layer-2" 是个不精确的标签.有些人说起 "Layer-2" 时,仅仅指的是 " ...
- iOS 兼容性处理
1. scroll滑动层,在iOS中滑动不流畅的处理 -webkit-overflow-scrolling:touch; //在滑动层标签添加这个样式 2. iOS 系统中input标签,去掉圆角效果 ...
- Hadoop生态常用数据模型
Hadoop生态常用数据模型 一.TextFile 二.SequenceFile 1.特性 2.存储结构 3.压缩结构与读取过程 4.读写操作 三.Avro 1.特性 2.数据类型 3.avro-to ...