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#
作者:weihanli
出处:https://www.cnblogs.com/weihanli/p/14530672.html
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?