ASP.NET 核心中内容类型"application/csp-report"的"415 Unsupported Media Type"



我有一项内容安全政策,导致 Chrome 发布报告,但接收报告的操作返回"415 不支持的媒体类型"。我知道这是因为该帖子的内容类型为"应用程序/csp-report"。如何将其添加为 Core 3.1 中允许的内容类型(它基本上只是 json(。

行动

// https://anthonychu.ca/post/aspnet-core-csp/
[HttpPost][Consumes("application/csp-report")]
public IActionResult Report([FromBody] CspReportRequest request)
{
return Ok();
}

模型的精简版

public class CspReportRequest
{
[JsonProperty(PropertyName = "csp-report")]
public CspReport CspReport { get; set; }
}
public class CspReport
{
[JsonProperty(PropertyName = "document-uri")]
public string DocumentUri { get; set; }
}

下面的示例演示如何向SystemTextJsonInputFormatter添加支持以处理其他媒体类型:

services.AddControllers(options =>
{
var jsonInputFormatter = options.InputFormatters
.OfType<SystemTextJsonInputFormatter>()
.Single();
jsonInputFormatter.SupportedMediaTypes.Add("application/csp-report");
});

这是一个两步过程:

  1. 询问配置的输入格式化程序列表以查找SystemTextJsonInputFormatter
  2. application/csp-report添加到其支持的媒体类型(application/jsontext/jsonapplication/*+json(的现有列表中。

如果您使用的是 Json.NET 而不是System.Text.Json,则方法类似

services.AddControllers(options =>
{
var jsonInputFormatter = options.InputFormatters
.OfType<NewtonsoftJsonInputFormatter>()
.First();
jsonInputFormatter.SupportedMediaTypes.Add("application/csp-report");
})

有两个小区别:

  1. 类型是NewtonsoftJsonInputFormatter而不是SystemTextJsonInputFormatter
  2. 集合中有两个这种类型的实例,因此我们针对第一个实例(有关详细信息,请参阅此答案(。

请参阅 ASP.NET Core 文档中的输入格式化程序以了解有关这些格式化程序的更多信息。

我想补充一点,接受的解决方案对我不起作用。(.NET Core 3.1(关于CSP报告,我有完全相同的用例。当尝试使用NewtonSoft并修改输入格式化程序NewtonsoftJsonInputFormatter以接受媒体标头类型application/csp-report时,我总是会收到一个异常,指出找不到输入格式化程序(有或没有.AddNewtonsoftJson();(

我设法通过执行以下操作来解决问题:

services.AddControllers().AddNewtonsoftJson();
services.AddOptions<MvcOptions>()
.PostConfigure<IOptions<JsonOptions>, IOptions<MvcNewtonsoftJsonOptions>, ArrayPool<char>, ObjectPoolProvider, ILoggerFactory>(
(mvcOptions, jsonOpts, newtonJsonOpts, charPool, objectPoolProvider, loggerFactory) =>
{
var formatter = mvcOptions.InputFormatters.OfType<NewtonsoftJsonInputFormatter>().First(i => i.SupportedMediaTypes.Contains("application/json"));
formatter.SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("application/csp-report"));
mvcOptions.InputFormatters.RemoveType<NewtonsoftJsonInputFormatter>();
mvcOptions.InputFormatters.Add(formatter);
});

我的模型和控制器操作与问题中发布的相同。

(我的解决方案来自如何配置两个 JSON 序列化程序并根据路由选择正确的序列化程序(

上周我遇到了同样的问题,并使用我自己的自定义格式化程序找到了替代解决方案:

using CspReportLogger.Models;
using Microsoft.AspNetCore.Mvc.Formatters;
using Microsoft.Net.Http.Headers;
using System;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
namespace CspReportLogger.Formatters
{
public class CSPReportInputFormatter : TextInputFormatter
{
public CSPReportInputFormatter()
{
// Specify the custom media type.
SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("application/csp-report"));
SupportedEncodings.Add(Encoding.UTF8);
}
public override async Task<InputFormatterResult> ReadRequestBodyAsync(InputFormatterContext context, Encoding effectiveEncoding)
{
// Let ASP interrupt deserialization
var cancellationToken = context.HttpContext.RequestAborted;
// Avoid InvalidCastException, pull type from controller
var modelType = context.ModelType;
// Deserialize the body using our models and the JsonSerializer.
var report = await JsonSerializer.DeserializeAsync(context.HttpContext.Request.Body, modelType, null, cancellationToken);
return await InputFormatterResult.SuccessAsync(report);
}
}
}

当然.cs必须在 Startup 中注册:

public void ConfigureServices(IServiceCollection services)
{
services.AddControllers(options =>
{
options.InputFormatters.Insert(0, new CSPReportInputFormatter());
});
}

我希望我早点看到柯克·拉金的解决方案,因为它显然更简洁。

我想自定义格式化程序解决方案很有帮助,如果你想接受无效的 json 的体型。

感谢 rm-code 为此。我确实必须进行一些更改,因为我在以下位置获得空值:

var report = await JsonSerializer.DeserializeAsync(context.HttpContext.Request.Body, modelType, null, cancellationToken);

这是最终对我有用的东西。

using Namespace.WebUI.Models;
using Microsoft.AspNetCore.Mvc.Formatters;
using Microsoft.Net.Http.Headers;
using Newtonsoft.Json;
using System.IO;
using System.Text;
using System.Threading.Tasks;
public class CSPReportInputFormatter : TextInputFormatter
{
public CSPReportInputFormatter()
{
// Specify the custom media type.
SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("application/csp-report"));
SupportedEncodings.Add(Encoding.UTF8);
}
public override async Task<InputFormatterResult> ReadRequestBodyAsync(InputFormatterContext context, Encoding effectiveEncoding)
{
using var reader = new StreamReader(context.HttpContext.Request.Body);
string responseString = await reader.ReadToEndAsync();
var data = JsonConvert.DeserializeObject<CspReportRequest>(responseString);
return await InputFormatterResult.SuccessAsync(data);
}
}

最新更新