我正在使用Microsoft ASP.NET Web API构建RESTful服务。
我的问题涉及Web API在出现错误时(例如400错误请求或404未找到)向用户抛出的HttpErrors。
问题是,我不想在响应内容中获得序列化的HttpError,因为它有时提供了太多信息,因此它违反了OWASP安全规则,例如:
请求:
http://localhost/Service/api/something/555555555555555555555555555555555555555555555555555555555555555555555
作为回应,我当然得到了400,但有以下内容信息:
{
"$id": "1",
"Message": "The request is invalid.",
"MessageDetail": "The parameters dictionary contains a null entry for parameter 'id' of non-nullable type 'System.Int32' for method 'MyNamespaceAndMethodHere(Int32)' in 'Service.Controllers.MyController'. An optional parameter must be a reference type, a nullable type, or be declared as an optional parameter."
}
这样的东西不仅表明我的WebService是基于ASP.NET WebAPI技术的(还不错),而且它还提供了一些关于我的命名空间、方法名、参数等的信息。
我试图在Global.asax 中设置IncludeErrorDetailPolicy
GlobalConfiguration.Configuration.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Never;
是的,这在某种程度上做得很好,现在结果不包含MessageDetail部分,但我仍然不想得到这个HttpError。
我还构建了我的自定义DelegatingHandler,但它也会影响我自己在控制器中生成的400和404,这是我不希望发生的。
我的问题是:有没有什么方便的方法可以从响应内容中消除序列化的HttpError?我只想让用户为他的错误请求返回响应代码。
使用自定义IHttpActionInvoker怎么样?基本上,您只需要发送一个空的HttpResponseMessage。
这里有一个非常基本的例子:
public class MyApiControllerActionInvoker : ApiControllerActionInvoker
{
public override Task<HttpResponseMessage> InvokeActionAsync(HttpActionContext actionContext, System.Threading.CancellationToken cancellationToken)
{
var result = base.InvokeActionAsync(actionContext, cancellationToken);
if (result.Exception != null)
{
//Log critical error
Debug.WriteLine("unhandled Exception ");
return Task.Run<HttpResponseMessage>(() => new HttpResponseMessage(HttpStatusCode.InternalServerError));
}
else if (result.Result.StatusCode!= HttpStatusCode.OK)
{
//Log critical error
Debug.WriteLine("invalid response status");
return Task.Run<HttpResponseMessage>(() => new HttpResponseMessage(result.Result.StatusCode));
}
return result;
}
}
在Global.asax 中
GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpActionInvoker), new MyApiControllerActionInvoker());
你可以做的另一件与WebApi无关的重要事情是删除过多的asp.net&IIS HTTP标头。这里有一个很好的解释。
我相信您使用消息处理程序的方法是正确的,因为无论Web API管道中的哪个组件将状态代码设置为4xx,消息处理程序都可以清除响应主体。但是,您确实希望区分显式设置的组件与其他组件设置的组件。这是我的建议,我承认它有点古怪。如果您没有其他更好的解决方案,请尝试一下。
在ApiController
类中,当抛出HttpResponseException
时,在请求属性中设置一个标志,如下所示
Request.Properties["myexception"] = true;
throw new HttpResponseException(...);
在消息处理程序中,检查该属性,如果设置了该属性,则不清除响应正文。
var response = await base.SendAsync(request, cancellationToken);
if((int)response.StatusCode > 399 && !request.Properties.Any(p => p.Key == "myException"))
response.Content = null;
return response;
您可以通过向HttpRequestMessage添加一个扩展方法来很好地封装它,这样ApiController
和消息处理程序都不知道我上面使用的硬编码字符串"myException"。