【问题标题】:Add custom header to all responses in Web API将自定义标头添加到 Web API 中的所有响应
【发布时间】:2013-12-19 09:49:48
【问题描述】:

简单的问题,我相信它有一个简单的答案,但我找不到。

我正在使用 WebAPI,我想将自定义标头发送回所有响应(开发人员出于同步目的而请求的服务器日期/时间)。

我目前正在努力寻找一个明确的示例,说明如何在一个地方(通过 global.asax 或另一个中心位置)获得一个自定义标题以显示所有响应。


答案已接受,这是我的过滤器(几乎相同)和我添加到 WebApi 配置的注册功能的行。

注意:DateTime 的东西是 NodaTime,没有真正的原因只是对它感兴趣。

    public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
    {
        actionExecutedContext.Response.Content.Headers.Add("ServerTime", Instant.FromDateTimeUtc(DateTime.Now.ToUniversalTime()).ToString());
    }

配置行:

config.Filters.Add(new ServerTimeHeaderFilter());

【问题讨论】:

    标签: c# asp.net asp.net-web-api


    【解决方案1】:

    为此,您可以使用自定义 ActionFilter (System.Web.Http.Filters)

    public class AddCustomHeaderFilter : ActionFilterAttribute
    {
        public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
        {
           actionExecutedContext.Response.Headers.Add("customHeader", "custom value date time");
        }
    }
    

    然后,您可以通过将过滤器添加到 Global.asax 的配置中来将过滤器应用于所有控制器的操作:

    GlobalConfiguration.Configuration.Filters.Add(new AddCustomHeaderFilter());
    

    您还可以将过滤器属性应用于您想要的操作,而无需全局配置行。

    【讨论】:

    • 这个答案大部分是正确的。但是,有时响应的内容可能是null。你应该改用actionExecutedContext.Response.Headers.Add。
    • 动作过滤器可以工作,但要小心消息处理程序可能会阻止你走得那么远。因此,您可能会遇到一些缺少标题的响应。
    • 另外,请记住授权过滤器在操作过滤器之前运行,如果您的授权过滤器拒绝访问,自定义操作过滤器将永远不会触发。
    • 这些答案的问题是他们只将标题应用于html页面,而不是CSS页面、图像、javascript等。这真的有问题吗?如果您使用 ZAP 运行渗透测试,它会抱怨缺少标头。如何为 MVC 应用程序中的所有文件添加标头?
    • OnActionExecuted 仅在执行操作时触发。因此,如果另一个过滤器阻止它执行,那么您的过滤器将不会运行。如果您有一个授权过滤器并且上下文未经过身份验证,并且您依靠您的操作过滤器在未经身份验证的请求上运行,这很常见。为了解决这个问题,您应该实现 OnActionExecuting,并同时实现它的异步和同步版本。
    【解决方案2】:

    以上两种解决方案都不适合我。他们甚至不会编译。这就是我所做的。补充:

    filters.Add(new AddCustomHeaderFilter());
    

    到FiltersConfig.cs中的RegisterGlobalFilters(GlobalFilterCollection filters)方法,然后添加

    public class AddCustomHeaderFilter : ActionFilterAttribute
    {
       public override void OnActionExecuted(ActionExecutedContext actionExecutedContext)
       {
           actionExecutedContext.HttpContext.Response.Headers.Add("ServerTime", DateTime.Now.ToString());
       }
    }
    

    【讨论】:

    • 我认为这是 WebAPI 1,不确定 2(如果这是您使用的)的绑定略有不同
    • 是的,很可能这就是解释。我正在使用 WebAPI 2.0。但我认为我的版本对现在正在寻找如何添加自定义标题的人很有用。
    • 我认为这在抛出异常时不起作用。如何为所有响应添加标题?
    【解决方案3】:

    Julian 的回答让我不得不创建过滤器,但只使用 System.Web (v4) 和 System.Web.Http (v5) 命名空间(MVC 包不属于这个使用的特定项目的一部分。)

    using System.Web;
    using System.Web.Http.Filters;
    ...
    public class AddCustomHeaderActionFilterAttribute : ActionFilterAttribute
    {
        public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
        {
            base.OnActionExecuted(actionExecutedContext);
            actionExecutedContext.ActionContext.Response.Headers.Add("name", "value");
        }
    }
    

    并将其添加到 global.asax 以便在每个控制器/动作上使用它

            GlobalConfiguration.Configuration.Filters.Add(new AddCustomHeaderActionFilterAttribute());
    

    【讨论】:

      【解决方案4】:

      此问题的先前答案并未说明如果您的控制器操作引发异常该怎么办。有两种基本方法可以让它发挥作用:

      添加异常过滤器:

      using System.Net;
      using System.Net.Http;
      using System.Web.Http.Filters;
      
      public class HeaderAdderExceptionFilter : ExceptionFilterAttribute
      {
          public override void OnException(HttpActionExecutedContext context)
          {
              if (context.Response == null)
                  context.Response = context.Request.CreateErrorResponse(
                      HttpStatusCode.InternalServerError, context.Exception);
      
              context.Response.Content.Headers.Add("header", "value");
          }
      }
      

      在您的 WebApi 设置中:

      configuration.Filters.Add(new HeaderAdderExceptionFilter());
      

      这种方法有效,因为 WebApi 的默认异常处理程序将发送在过滤器中创建的 HttpResponseMessage,而不是构建自己的。

      替换默认异常处理程序:

      using System.Net;
      using System.Net.Http;
      using System.Web.Http.ExceptionHandling;
      using System.Web.Http.Results;
      
      public class HeaderAdderExceptionHandler : ExceptionHandler
      {
          public override void Handle(ExceptionHandlerContext context)
          {
              HttpResponseMessage response = context.Request.CreateErrorResponse(
                  HttpStatusCode.InternalServerError, context.Exception);
              response.Headers.Add("header", "value");
      
              context.Result = new ResponseMessageResult(response);
          }
      }
      

      在您的 WebApi 设置中:

      configuration.Services.Replace(typeof(IExceptionHandler), new HeaderAdderExceptionHandler());
      

      您不能同时使用这两种方法。好吧,你可以,但是处理程序永远不会做任何事情,因为过滤器已经将异常转换为响应。

      非常重要的是要注意如所写,此代码会将所有异常详细信息发送给客户端。您可能不想在生产环境中执行此操作,因此请检查 CreateErrorResponse() 上所有可用的重载,然后选择适合您需要的重载。

      【讨论】:

        【解决方案5】:

        我将正常路径和异常路径合并到一个类中:

        public class CustomHeaderAttribute : FilterAttribute, IActionFilter, IExceptionFilter
        {
            private static string HEADER_KEY   { get { return "X-CustomHeader"; } }
            private static string HEADER_VALUE { get { return "Custom header value"; } }
        
            public Task<HttpResponseMessage> ExecuteActionFilterAsync(HttpActionContext actionContext, CancellationToken cancellationToken, Func<Task<HttpResponseMessage>> continuation)
            {
                return (new CustomHeaderAction() as IActionFilter).ExecuteActionFilterAsync(actionContext, cancellationToken, continuation);
            }
        
            public Task ExecuteExceptionFilterAsync(HttpActionExecutedContext actionExecutedContext, CancellationToken cancellationToken)
            {
                return (new CustomHeaderException() as IExceptionFilter).ExecuteExceptionFilterAsync(actionExecutedContext, cancellationToken);
            }
        
            private class CustomHeaderAction: ActionFilterAttribute
            {
                public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
                {
                    if (actionExecutedContext.Response != null)
                    { 
                        actionExecutedContext.Response.Content.Headers.Add(HEADER_KEY, HEADER_VALUE);
                    }
                }
            }
        
            private class CustomHeaderException : ExceptionFilterAttribute
            {
                public override void OnException(HttpActionExecutedContext context)
                {
                    if (context.Response == null)
                    {
                        context.Response = context.Request.CreateErrorResponse(HttpStatusCode.InternalServerError, context.Exception);
                    }
        
                    context.Response.Content.Headers.Add(HEADER_KEY, HEADER_VALUE);
                }
            }
        }
        

        没什么特别的,但至少它给了我一个地方来控制我的额外标题。目前它只是静态内容,但您始终可以将其连接到某种字典生成器/工厂。

        【讨论】:

          【解决方案6】:

          根据我的要求,下面一行代码就可以了。

          System.Web.HttpContext.Current.Response.Headers.Add("Key", "Value")
          

          【讨论】:

          • IEnumerable&lt;string&gt; vals;response.Headers.TryGetValues("Key", out vals);string value = vals?.FirstOrDefault();
          【解决方案7】:

          我在尝试向整个控制器添加新标头时遇到了同样的问题,只需添加“services.AddHttpContextAccessor();”到 startup.cs 然后创建你的控制器

          public class EnController : Controller{
          
                  public EnController(IHttpContextAccessor myHttpAccessor)
                  {
          
                      myHttpAccessor.HttpContext.Response.Headers.Add("Content-Language", "en-US");
          
                  }
          
                 ... more methods here... 
          
          }

          【讨论】:

            【解决方案8】:

            messagehandler 可以轻松完成,它会同时处理 ok 响应和异常情况。

             public class CustomHeaderHandler : DelegatingHandler
            {
                protected override async Task<HttpResponseMessage> SendAsync(
                    HttpRequestMessage request, CancellationToken cancellationToken)
                {
                   // add header to request if you want
                    var response = await base.SendAsync(request, cancellationToken);
                    response.Headers.Add("cutomKey", "cutomValue");
                    return response;
                }
            }
            

            在配置中添加

             config.MessageHandlers.Add(new CustomHeaderHandler());
            

            【讨论】:

              猜你喜欢
              • 2018-02-21
              • 1970-01-01
              • 2012-11-09
              • 2019-02-06
              • 1970-01-01
              • 2012-11-09
              • 2013-09-18
              • 2018-10-04
              • 2019-06-10
              相关资源
              最近更新 更多