我正在尝试从web.api返回自定义错误响应。让它是格式化为json的简单字符串"Oops!"
。所以我创建了简单的委托处理程序来替换错误响应,如下所示:
public class ErrorMessageHandler : DelegatingHandler
{
protected override async Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request, CancellationToken cancellationToken)
{
var response = await base.SendAsync(request, cancellationToken);
if (response.IsSuccessStatusCode)
return response;
var formatter = new JsonMediaTypeFormatter();
var errorResponse = request.CreateResponse(response.StatusCode, "Oops!", formatter);
return errorResponse;
}
}
接下来,我确保这是管道中唯一的一个消息处理程序:
httpConfig.MessageHandlers.Clear();
httpConfig.MessageHandlers.Add(new ErrorMessageHandler());
// Only default route
httpConfig.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
app.UseWebApi(httpConfig); // OWIN self-hosting
控制器也是最简单的一个:
public class ValuesController : ApiController
{
public IHttpActionResult Get(int id)
{
if (id == 42)
return Ok("Answer to the Ultimate Question of Life, the Universe, and Everything");
return NotFound();
}
}
这很有趣:
/api/values/42
为我提供了200个带有值字符串/api/values/13
通过我的自定义"Oops!"
字符串/api/values/42/missing
为我提供空 404回复最后一个案例是我的问题。当我在委托处理程序的最后一行设置断点时,我清楚地看到errorResponse
包含ObjectContent<string>
且值正确。但为什么这个价值会在以后清除掉呢?
答案 0 :(得分:2)
原因是HttpMessageHandlerAdapter.InvokeCore中的代码(基本上在UseWebApi
中间件中):
response = await _messageInvoker.SendAsync(request, cancellationToken);
// ...
if (IsSoftNotFound(request, response)) {
callNext = true;
}
else {
// ...
}
IsSoftNotFound
的位置:
private static bool IsSoftNotFound(HttpRequestMessage request, HttpResponseMessage response)
{
if (response.StatusCode == HttpStatusCode.NotFound)
{
bool routingFailure;
if (request.Properties.TryGetValue<bool>(HttpPropertyKeys.NoRouteMatched, out routingFailure)
&& routingFailure)
{
return true;
}
}
return false;
}
所以基本上是在&#34; soft&#34; 404,其中&#34;软&#34;表示没有匹配的路由(并且由request.Properties
中的特定键的属性指示) - 中间件将调用下一个组件。否则 - 只会发送回复。
这个IsSoftDelete
适用于您的情况(因为确实没有路由匹配),而下一个组件(没有时间弄清楚那是什么)会清除您的响应内容。
To&#34; fix&#34;此问题 - 在请求由前一个处理程序处理后,从请求中删除具有该键的属性:
public class ErrorMessageHandler : DelegatingHandler {
protected override async Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request, CancellationToken cancellationToken) {
var response = await base.SendAsync(request, cancellationToken);
if (response.IsSuccessStatusCode)
return response;
// here, can also check if 404
request.Properties.Remove(HttpPropertyKeys.NoRouteMatched);
var formatter = new JsonMediaTypeFormatter();
var errorResponse = request.CreateResponse(response.StatusCode, "Oops!", formatter);
return errorResponse;
}
}