![](/img/trans.png)
[英]415 Status When Passing Model into Controller Action in ASP.NET Core 3.1 MVC
[英]How to create a custom response for HTTP status 415 in ASP.NET Core 3.1?
我正在创建一个 ASP.NET Core ( .NET Core 3.1 ) API 接受内容为 JSON 的请求。
如果我 POST 到我的端点非 JSON 请求内容(同时在 VS 中使用 IIS Express 调试运行)我得到类似于以下的响应:
{
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.13",
"title": "Unsupported Media Type",
"status": 415,
"traceId": "|a53c33b7-43fa646efa5c6ab9."
}
我不想在响应中发送这个,而是想为这种情况创建我自己的响应。 如果可能的话,我想通过改变管道来做到这一点。
在我的Startup.cs
,我添加了:
public void Configure(IApplicationBuilder app)
{
app.Use(async (context, next) =>
{
await next.Invoke();
if (context.Response.StatusCode == StatusCodes.Status415UnsupportedMediaType)
{
await context.Response.WriteAsync("Unsupported media type handled");
}
});
// other calls on app
}
但是,在运行该应用程序并到达我的端点后,我现在得到:
{
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.13",
"title": "Unsupported Media Type",
"status": 415,
"traceId": "|3ec437d7-4b20f64c28d04f16."
}Unsupported media type handled
我试过调用context.Response.Clear();
在我写我的新文本之前,但这只是输出上面的 JSON 而没有我的自定义文本。 这似乎更奇怪。
这里发生了什么? 在我的管道开始之前,感觉好像有什么东西正在处理和创建 415 响应。 或者我可能做错了什么?
我强烈建议您重新考虑您最初的想法,即用您自己的自定义响应内容替换您从 ASP.NET 核心获得的响应内容。
ASP.NET 核心对 API 控制器的错误处理有意见。 他们决定使用问题详细信息规范来处理一些客户端错误(例如 415 状态代码)。
问题详细信息 RFC中的引述:
本文档将“问题详细信息”定义为一种在 HTTP 响应中携带机器可读错误详细信息的方法,以避免需要为 HTTP API 定义新的错误响应格式。
HTTP [RFC7230] 状态代码有时不足以传达有关错误的足够信息以提供帮助。 虽然 Web 浏览器背后的人类可以通过 HTML [W3C.REC-html5-20141028] 响应主体了解问题的性质,但所谓的“HTTP API”的非人类消费者通常不会。
本规范定义了简单的 JSON [RFC7159] 和 XML [W3C.REC-xml-20081126] 文档格式来满足此目的。 它们旨在供 HTTP API 重用,这些 API 可以识别特定于其需求的不同“问题类型”。
这是一个 web 标准,用于在机器之间传达错误,因此在 API 控制器错误处理的上下文中,这是一个有意义的选择。
请注意,该标准旨在通过定义自定义错误契约来传达来自 web api 的错误并必须为客户记录它们,从而避免每次都重新发明轮子。
本文档说明,对于某些指示客户端错误的 HTTP 状态代码(例如:您的415 Unsupported Media Type状态代码),符合问题详细信息规范的 JSON 响应由 ASP.NET 核心框架自动创建。
您在这里有几个选择:
ApiBehaviorOptions.SuppressMapClientErrors = true;
. 这样你会得到一个简单的状态代码(在你的情况下是 415 状态代码)作为响应,根本没有响应内容。ProblemDetailsFactory
实现,如此处所述我会避免选项 3。
在我看来,如果您真的想自定义包含在问题详细信息 JSON object 中的错误消息,那么您可以做的最好的事情就是坚持使用选项 2。
这是一个例子:
public void ConfigureServices(IServiceCollection services)
{
services
.AddControllers()
.ConfigureApiBehaviorOptions(options =>
{
options.ClientErrorMapping[415].Title = "My custom message";
});
}
您将得到的响应内容(对于无效请求,例如没有内容的请求)如下:
您可以评估的另一个选项是选项 1:抑制由 ASP.NET 核心完成的默认客户端错误处理,并在 415 响应状态代码的情况下完全控制响应。
这是一个例子:
public void ConfigureServices(IServiceCollection services)
{
services
.AddControllers()
.ConfigureApiBehaviorOptions(options =>
{
options.SuppressMapClientErrors = true;
});
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.Use(async (context, next) =>
{
await next();
// Handle the 415 response
if (context.Response.StatusCode == 415)
{
context.Response.ContentType = "application/json";
var json = JsonSerializer.Serialize(new { message = "You need to add a request body!" });
await context.Response.WriteAsync(json);
}
});
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
您将获得的响应负载(对于无效请求,例如没有内容的请求)如下:
请注意,在这里我能够完全控制响应内容,因为通过禁用由 ASP.NET 核心 ( options.SuppressMapClientErrors = true;
) 完成的默认客户端错误映射,发送无效 POST 请求时得到的响应是一个普通的415状态码,完全没有响应内容。 因此,当写入响应 stream ( await context.Response.WriteAsync(json);
) 时,您正在写入一个空响应 stream,因此只有我们自定义的 JSON 作为响应内容发送到客户端。
在您的第一次尝试中,您忘记禁用 ASP.NET 核心在 415 响应状态代码的情况下创建的自动响应,因此代码await context.Response.WriteAsync("Unsupported media type handled");
正在将内容附加到响应 stream,响应内容已经由 ASP.NET 核心框架自动写入。
从这里
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler(exceptionHandlerApp =>
{
exceptionHandlerApp.Run(async context =>
{
context.Response.StatusCode = StatusCodes.Status500InternalServerError;
// using static System.Net.Mime.MediaTypeNames;
context.Response.ContentType = Text.Plain;
await context.Response.WriteAsync("An exception was thrown.");
var exceptionHandlerPathFeature =
context.Features.Get<IExceptionHandlerPathFeature>();
if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
{
await context.Response.WriteAsync(" The file was not found.");
}
if (exceptionHandlerPathFeature?.Path == "/")
{
await context.Response.WriteAsync(" Page: Home.");
}
});
});
app.UseHsts();
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.