【问题标题】:ASP.NET 5 Middleware "no response received" after adding header添加标头后 ASP.NET 5 中间件“未收到响应”
【发布时间】:2015-10-01 11:15:41
【问题描述】:
public class MyMiddleware
{
    RequestDelegate _next;

    public MyMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task Invoke(HttpContext context)
    {

        //await context.Response.WriteAsync("Hello!");
        await _next(context);
        context.Response.Headers.Add("X-ElapsedTime", new[] { "bla" });
    }
}

只要我添加类似标题的内容。我无法再收到来自我的 Web API 控制器的响应。

 public void Configure(IApplicationBuilder app, IHostingEnvironment env)
 {
     app.UseMyMiddleware();
     app.UseMvc();
 }

我需要先阅读以下中间件“UseMvc”产生的答案吗?

我只有一个非常简单的Controller方法:

    // GET: api/values
    [HttpGet]
    public IEnumerable<string> Get()
    {
        //Task t = new Task(() => Thread.Sleep(2000));
        //t.Start();

        return new string[] { "value1", "value2" };
    }

我想我找到了解决方案,但实际上并不是一个完整的答案:

 public class MyMiddleware
{
    RequestDelegate _next;
    HttpContext _context;

    public MyMiddleware(RequestDelegate next)
    {
        _next = next;
    }
    public async Task Invoke(HttpContext context)
    {
        _context = context;
        context.Response.OnStarting(OnStartingCallback, state: this);
        await _next(context);
    }
    public Task OnStartingCallback(object state)
    {
        _context.Response.Headers.Set("x-bla", "bla");
        return Task.FromResult(0);
    }
}

我找到了一个参考:https://github.com/aspnet/Session/blob/master/src/Microsoft.AspNet.Session/SessionMiddleware.cs 并尝试根据它构建我的代码。

无论如何,这段代码感觉不是很安全。它真的是线程安全的吗?

【问题讨论】:

    标签: asp.net asp.net-web-api asp.net-core


    【解决方案1】:

    基本上发生的情况是,在将任何内容写入响应正文后,您无法设置任何标头。

    这是因为标头是在正文之前发送的,并且只要设置了任何正文内容。

    要以适当的方式绕过它,就是缓冲响应并且在所有中间件都执行之前不发送任何内容,以便它们有机会修改标头。这种行为应该是 Web 服务器的责任。不幸的是,我没有找到任何有用的信息如何在 ASP.NET 5(IIS 或 Kestrel)上配置缓冲。

    您的解决方案似乎没问题,但它不是线程安全的。中间件是单例的,当多个并发请求可能到达您的服务器时,在类字段中保存上下文可能会引入竞争条件。 您可以通过将上下文作为状态对象传递来使其成为线程安全的。

    context.Response.OnStarting(OnStartingCallback, state: context);
    

    然后通过将object state 转换为HttpContext 在回调中检索它。

    【讨论】:

    • 谢谢,这听起来像是早期 PHP 开发中已经发送的 HTTP 标头问题。 “状态:这个”甚至有意义吗?在这种特殊情况下,状态对象将始终指向同一个类实例。还是按值调用。在 C# 中总是不确定它是按值调用还是按引用调用。
    • 它总是指向同一个 MyMiddleware 类的实例。但是因为中间件只被实例化一次,它将是所有请求的同一个实例。这就是为什么你不应该在那里使用 'this' 关键字并传递上下文。
    • 我根据您的建议修改了我的代码(状态:上下文)。如何在此上下文中添加更多变量?我正在启动秒表来测量请求时间 (gist.github.com/MatthiasJost/83269e5d199bcc48b882)
    猜你喜欢
    • 1970-01-01
    • 2021-12-12
    • 2018-08-15
    • 1970-01-01
    • 1970-01-01
    • 2015-04-10
    • 2021-11-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多