【问题标题】:Set response header in middleware when using ActionResult使用 ActionResult 时在中间件中设置响应头
【发布时间】:2021-05-08 20:19:13
【问题描述】:

我有一个 asp .net core web api,我需要在响应中设置一些标头。这基于响应的正文。 (计算md5)

我想在自定义中间件中执行此操作,以便每个请求都具有相同的响应标头。

我尝试了以下设置:

首先我有一个带有简单端点的控制器:

[Route("api/[controller]")]
[ApiController]
public class TestController : ControllerBase
{
    [HttpGet]
    [Route("Test")]
    public IActionResult DoTest()
    {
        var result = new { someProp = "somePropValue" };
        return Ok(result);
    }
}

我添加了一个自定义中间件类:

public class CustomResponseHandler
{
    private readonly RequestDelegate _next;

    public CustomResponseHandler(RequestDelegate next)
    {
        _next = next;
    }
    public async Task InvokeAsync(HttpContext context)
    {
        await _next(context);
        context.Response.Headers.Add("foo", "fii");
    }
}

在启动时,我使用 Configure 方法添加了这个中间件:

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        app.UseHttpsRedirection();

        app.UseRouting();

        app.UseAuthorization();

        app.UseMiddleware<CustomResponseHandler>();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllers();
        });
    }

当我运行它时, context.Response.Headers.Add("foo", "fii");行确实被执行了。

从完美的端点返回结果后也会执行。

但是,当我查看响应时,仍然缺少标题“foo”。

有没有办法做到这一点。

我注意到在将结果返回端点之前添加标题时确实得到了标题:

    public IActionResult DoTest()
    {
        var result = new { someProp = "somePropValue" };
        Response.Headers.Add("foo", "fii");
        return Ok(result);
    }

【问题讨论】:

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


    【解决方案1】:

    next() 在您的中间件中执行时,服务器已经开始向客户端发送响应。这意味着不能再修改标题。引用此Microsoft Docs

    不要调用 next.Invoke 在响应发送到客户端之后。响应开始后对 HttpResponse 的更改会引发异常。例如,设置标头和状态代码会引发异常。调用 next 后写入响应正文:

    • 可能会导致协议违规。例如,写入超过规定的 Content-Length。

    • 可能会破坏正文格式。例如,将 HTML 页脚写入 CSS 文件。

    你应该做的是在调用next()之前添加标题,或者将它添加到Response.OnStarting的钩子中:

    public async Task InvokeAsync(HttpContext context)
    {
        context.Response.OnStarting(() =>
        {
            context.Response.Headers.Add("foo", "fii");
            return Task.CompletedTask;
        });
        await next();
    }
    

    【讨论】:

    • 谢谢!我试过了,这确实添加了标题。但是,我无法访问此回调中的响应正文。 (我想它还没有填写)。所以不知道这个回调是否可以计算出一个md5哈希或者内容长度?
    • 在这种情况下,您可能需要replace the response stream with your own seekable and readable stream。这将使您更好地控制流,例如倒带并从中重新读取,获取其长度等。在这种情况下,您不需要OnStarting 回调。请注意,这可能会影响性能或内存。
    • 好的,谢谢您的洞察力!看到其中的含义,我意识到这可能不是最好的前进方式,而是会以不同的方式实施。
    猜你喜欢
    • 1970-01-01
    • 2017-05-15
    • 1970-01-01
    • 2018-09-01
    • 2023-03-16
    • 2017-09-08
    • 2013-08-02
    • 1970-01-01
    • 2019-04-01
    相关资源
    最近更新 更多