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 =https://www.cnblogs.com/weihanli/p/> 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 = https://www.cnblogs.com/weihanli/p/await GetModelValue(services, bytes);
return await InputFormatterResult.SuccessAsync(modelValue);
async ValueTask
上述代碼兼容了使用 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
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/270429.html
標籤:.NET Core
