<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          ASP.NET Core 自定義 Content-Type

          共 7050字,需瀏覽 15分鐘

           ·

          2021-03-30 21:32

          asp.net core 實(shí)現(xiàn)支持自定義 Content-Type

          Intro

          我們最近有一個(gè)原本是內(nèi)網(wǎng)的服務(wù)要上公網(wǎng),在公網(wǎng)上有一層 Cloudflare 作為網(wǎng)站的公網(wǎng)流量提供者,CloudFlare 會(huì)有一層防火墻攔截掉一些非法的請(qǐng)求,我們有一些 API 會(huì)提交一些 html 內(nèi)容,經(jīng)過(guò) Cloudflare 的時(shí)候會(huì)被 Cloudflare 攔截,導(dǎo)致某些功能不能夠正常使用,于是就想對(duì)提交的數(shù)據(jù)進(jìn)行一個(gè)編碼之后再提交,服務(wù)器端針對(duì)需要解碼的請(qǐng)求進(jìn)行解碼再解析,我們新加了一個(gè) Content-Type 的支持,編碼后的數(shù)據(jù)使用新的 Content-Type,對(duì)于不編碼的數(shù)據(jù)依然可以工作,目前我們做了一個(gè)簡(jiǎn)單的 base64 編碼,如果需要的話(huà)也可以實(shí)現(xiàn)復(fù)雜一些的加密、壓縮等。

          Basis

          asp.net core 默認(rèn)支持 JSON 請(qǐng)求,因?yàn)閮?nèi)置了針對(duì) JSON 內(nèi)容的 Formatter,.NET Core 2.x 使用的是 Newtonsoft.Json 作為默認(rèn) JSON formatter,從 .NET Core 3.0 開(kāi)始引入了 System.Text.Json 作為默認(rèn)的 JSON formatter,如果要支持 XML 需要引入針對(duì) XML 的 formatter,相應(yīng)的如果需要增加其他類(lèi)型的請(qǐng)求實(shí)現(xiàn)自己的 formatter 就可以了

          Formatter 分為 InputFormatterOutputFormatter

          • InputFormatter 用來(lái)解析請(qǐng)求 Body 的數(shù)據(jù),將請(qǐng)求參數(shù)映射到強(qiáng)類(lèi)型的 model,Request Body => Value
          • OutputFormatter 用來(lái)將強(qiáng)類(lèi)型的數(shù)據(jù)序列化成響應(yīng)輸出,Value => Response Body

          Formatter 需要指定支持的 MediaType,可以理解為請(qǐng)求類(lèi)型,體現(xiàn)在請(qǐng)求頭上,對(duì)于 InputFormatter 對(duì)應(yīng)的就是  Content-Type ,對(duì)于 OutputFormatter 對(duì)應(yīng)的是 Accept,asp.net core 會(huì)根據(jù)請(qǐng)求信息來(lái)選擇注冊(cè)的 formatter。

          Sample

          先來(lái)看一下實(shí)現(xiàn)效果吧,實(shí)現(xiàn)效果如下:

          swagger

          swagger 的支持也算比較好了,在增加了新的 Content-Type 支持之后在 swagger 上可以看得到,而且可以切換請(qǐng)求的 Content-Type,上圖中的 text/base64-json 就是我自定義的一個(gè) Content-Type

          默認(rèn)請(qǐng)求:

          json-request

          對(duì)原始請(qǐng)求進(jìn)行 base64 編碼,再請(qǐng)求:

          base64-json-request

          Implement

          實(shí)現(xiàn)代碼如下:

          public class Base64EncodedJsonInputFormatter : TextInputFormatter
          {
              public Base64EncodedJsonInputFormatter()
              {
                  // 注冊(cè)支持的 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<objectGetModelValue(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,在發(fā)生異常時(shí)將錯(cuò)誤信息添加一個(gè) ModelError 以便在前端可以得到錯(cuò)誤信息的反饋,例如傳一個(gè)不合法的 base64 字符串就會(huì)像下面這樣:

          error

          實(shí)際使用的時(shí)候,只需要在 Startup 里配置一下就可以了,如:

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

          More

          通過(guò)自定義 Content-Type 的支持我們可以無(wú)侵入的實(shí)現(xiàn)不同的請(qǐng)求內(nèi)容,上面的示例代碼可以在 Github 上獲取 https://github.com/WeihanLi/SamplesInPractice/tree/master/AspNetCoreSample,可以根據(jù)自己的需要進(jìn)行自定義

          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







          回復(fù) 【關(guān)閉】學(xué)關(guān)
          回復(fù) 【實(shí)戰(zhàn)】獲取20套實(shí)戰(zhàn)源碼
          回復(fù) 【被刪】學(xué)個(gè)
          回復(fù) 【訪(fǎng)客】學(xué)訪(fǎng)
          回復(fù) 【小程序】學(xué)獲取15套【入門(mén)+實(shí)戰(zhàn)+賺錢(qián)】小程序源碼
          回復(fù) 【python】學(xué)微獲取全套0基礎(chǔ)Python知識(shí)手冊(cè)
          回復(fù) 【2019】獲取2019 .NET 開(kāi)發(fā)者峰會(huì)資料PPT
          回復(fù) 【加群】加入dotnet微信交流群

          臥槽:微信可以這樣換個(gè)字體了!


          副業(yè)剛需:這個(gè)開(kāi)源小程序外賣(mài)紅包項(xiàng)目,有人月入5000+!



          瀏覽 78
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  亚洲专区在线播放 | 日本无码操逼视频 | 刘玥一级婬片A片AAA | 国产精品乱码一区二三区小蝌蚪 | 美女露出粉嫩的尿囗桶爽 |