ASP.NET Web API从响应中删除HttpError

时间:2013-07-11 09:14:09

标签: asp.net asp.net-web-api response http-error

我正在使用Microsoft ASP.NET Web API构建RESTful服务。

我的问题涉及Web API在出现问题时返回给用户的HttpErrors(例如400 Bad Request或404 Not Found)。

问题是,我不想在响应内容中获得序列化的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?所有我希望用户回复他的错误请求是响应代码。

2 个答案:

答案 0 :(得分:2)

使用自定义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());

另一个与Web Api无关的重要事项是删除过多的asp.net&amp; IIS HTTP标头。 Here是一个很好的解释。

答案 1 :(得分:1)

我相信您使用消息处理程序的方法是正确的,因为无论Web API管道中将状态代码设置为4xx的组件,消息处理程序都可以清除响应正文。但是,您确实需要区分明确设置的与其他组件设置的那些。这是我的建议,我承认它有点hacky。如果您没有得到任何其他更好的解决方案,请尝试一下。

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”。