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 => Value
- OutputFormatter 用来将强类型的数据序列化成响应输出,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();