【问题标题】:How to add custom header to ASP.NET Core Web API response如何将自定义标头添加到 ASP.NET Core Web API 响应
【发布时间】:2018-02-21 07:36:20
【问题描述】:

我正在将我的 API 从 Web API 2 移植到 ASP.NET Core Web API。我以前可以通过以下方式添加自定义标题:

  HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK);
  response.Headers.Add("X-Total-Count", count.ToString());
  return ResponseMessage(response);

如何在 ASP.NET Core Web API 中添加自定义标头?

【问题讨论】:

标签: c# asp.net-core-webapi


【解决方案1】:

其他中间件可能会在您设置标头后清除它们。为确保您的标头已添加,请在发送响应之前添加它们。

app.Use(async (context, next) => {
    context.Response.OnStarting(() => {
        context.Response.Headers.Add("X-Developed-By", "Your Name");
        return Task.FromResult(0);
    });

    await next();
});

或者在真正的中间件中

public class AddHeadersMiddleware : IMiddleware
{
    public async Task InvokeAsync(HttpContext context, RequestDelegate next)
    {
        context.Response.OnStarting(() => {
            context.Response.Headers.Add("X-Developed-By", "Your Name");
            return Task.FromResult(0);
        });

        await next();
    }
}

【讨论】:

    【解决方案2】:

    我同意@Ho3Ein 的观点

    如果您想为所有请求添加自定义标头,中间件是最好的方法

    但不鼓励直接在中间件中修改Resposne。来自微软Doc

    响应开始后对 HttpResponse 的更改,抛出异常。例如,设置标头和状态码等更改会引发异常。

    app.Use(async (context, next) =>
            {
                // Do work that doesn't write to the Response.
                await next.Invoke();
                // Do logging or other work that doesn't write to the Response.
            });
    

    因此,在中间件中添加自定义标头的更好方法是使用Response.OnStarting 回调,如下所示:

    app.Use(async (context, next) =>
                          {
    
                              context.Response.OnStarting(() =>
                                  {
                                      context.Response.Headers.Add("X-Developed-By", "Your Name");
                                      return Task.FromResult(0);
                                  });
    
                              await next();
                          }
                          );
    

    【讨论】:

    • 看起来不错,但我怎样才能将请求返回的记录数传递给那里?
    【解决方案3】:

    对于任何想要为所有请求添加自定义标头的人来说,中间件是最好的方法。 像这样在 startup.cs 中进行一些更改:

    app.Use(async (context, next) =>
    {
       context.Response.Headers.Add("X-Developed-By", "Your Name");
       await next.Invoke();
    });
    

    祝你好运。

    【讨论】:

    • 不鼓励直接在中间件中修改响应,请参阅here。相反,您可以使用context.Response.OnStarting 回调。
    • 这在我捕获异常的中间件中不起作用。 DeveloperExceptionPageMiddleware 将删除我的标题。 @Mojtaba 下面的解决方案有效。
    • @BoukeVersteegh 这在您测试的特定情况下肯定不起作用。问题不是解决方案
    【解决方案4】:

    FWIW,如果你有 ApiController,而不是 Controller,你可以这样做:

    public class InfoController : ApiController
    {
        // Without custom header
        public IHttpActionResult MyMethod(..)
        {
            var myObject= GetMyResult();
            return Ok(myObject);
        }
    
        // With custom header
        public IHttpActionResult MyMethod(..)
        {
            var myObject = GetMyResult();
    
            // inspired from https://docs.microsoft.com/en-us/aspnet/web-api/overview/formats-and-model-binding/content-negotiation#how-content-negotiation-works
            var negotiator = Configuration.Services.GetContentNegotiator();
            var result = negotiator.Negotiate(typeof(TypeOfMyObject), Request, Configuration.Formatters);
            var msg = new HttpResponseMessage(HttpStatusCode.OK)
            {
                Content = new ObjectContent<TypeOfMyObject>(myObject, result.Formatter,result.MediaType.MediaType)
            };
    
            msg.Headers.Add("MyCustomHeader", "MyCustomHeaderValue");
            return ResponseMessage(msg);
        }
    }
    

    【讨论】:

    • ApiController 是 Microsoft.AspNetCore.Mvc.WebApiCompatShim.dll 的一部分,它是一种临时解决方案,可轻松从 asp.net 4.x 迁移到 asp.net 核心。对于新代码,我不会使用 ApiController。
    【解决方案5】:

    自定义属性可能是个好方法。

    https://docs.microsoft.com/en-us/aspnet/core/mvc/controllers/filters?view=aspnetcore-2.2

    public class AddHeaderAttribute : ResultFilterAttribute
    {
        private readonly string _name;
        private readonly string _value;
    
        public AddHeaderAttribute(string name, string value)
        {
            _name = name;
            _value = value;
        }
    
        public override void OnResultExecuting(ResultExecutingContext context)
        {
            context.HttpContext.Response.Headers.Add(_name, new string[] { _value });
            base.OnResultExecuting(context);
        }
    }
    

    然后像这样在你的 API 方法上使用它

    [AddHeader("X-MyHeader", "123"]
    

    如果你有一个共同的标题,你可以扩展这个类:

    public class MySpecialHeaderAttribute : AddHeaderAttribute
    {
        public MySpecialHeaderAttribute() : base("X-MyHeader", "true")
        {
        }
    }
    

    【讨论】:

      【解决方案6】:

      有一个简单的GET 操作示例,它从某个列表返回顶部的X 记录以及响应标头X-Total-Count 中的count

      using System;
      using System.Linq;
      using System.Net;
      using Microsoft.AspNetCore.Mvc;
      
      namespace WebApplication.Controllers
      {
          [Route("api")]
          public class ValuesController : Controller
          {
              [HttpGet]
              [Route("values/{top}")]
              public IActionResult Get(int top)
              {
                  // Generate dummy values
                  var list = Enumerable.Range(0, DateTime.Now.Second)
                                       .Select(i => $"Value {i}")
                                       .ToList();
                  list.Reverse();
      
                  var result = new ObjectResult(list.Take(top))
                  {
                      StatusCode = (int)HttpStatusCode.OK
                  };
      
                  Response.Headers.Add("X-Total-Count", list.Count.ToString());
      
                  return result;
              }
          }
      }
      

      URL 看起来像 http://localhost:3377/api/values/5,结果(生成 19 条虚拟记录,因此 X-Total-Count 的值将是 19)如下:

      ["Value 18","Value 17","Value 16","Value 15","Value 14"]
      

      【讨论】:

      • 感觉很hacky,因为我们基本上是在两个地方设置结果和属性。它可以封装在自定义操作结果中。在我打字时,我正要创建一个 ContentResultWithHeaders。不过话虽如此,感觉还是费了一番功夫。
      • 基类Microsoft.AspNetCore.Mvc.Controller 已经包含属性Response。因此,可以直接调用Response.Headers,而不是调用Request.HttpContext.Response.Headers
      【解决方案7】:

      您可以从传入的 Http Request 中劫持 HttpContext,并在调用 return 之前将您自己的自定义标头添加到 Response 对象。

      如果您希望自定义标头持续存在并添加到跨多个控制器的所有 API 请求中,那么您应该考虑制作一个 Middleware 组件来为您执行此操作,然后将其添加到 中的 Http 请求管道中Startup.cs

      public IActionResult SendResponse()
      {
          Response.Headers.Add("X-Total-Count", "20");
      
          return Ok();
      }    
      

      【讨论】:

      • 为了在 fetch api 中获得附加值,你需要在fetch(url).then((response) =&gt; { console.log(response.headers.get('X-Total-Count')); return response.text(); })之后写这个
      猜你喜欢
      • 1970-01-01
      • 2013-12-19
      • 2012-11-09
      • 1970-01-01
      • 2018-08-15
      • 1970-01-01
      • 2012-11-09
      • 2013-09-18
      • 2021-12-28
      相关资源
      最近更新 更多