繁体   English   中英

在 ASP.NET Core 中修改静态文件响应

[英]Modify static file response in ASP.NET Core

我使用app.UseStaticFiles()在我的应用程序中提供了一堆静态文件。 我想在发送之前为特定 HTML 文件的响应注入一些额外的标记。 我的第一次尝试是在静态文件中间件之前添加这样的中间件:

app.Use(async (context, next) => {
    await next();

    // Modify the response here
});

但是,这不起作用,因为我实际上无法读取读取响应流 - 它在引擎盖下使用 Kestrel 的FrameResponseStream ,这是不可读的。

所以,我想我可以用我可以写入的MemoryStream替换响应正文流:

app.Use(async (context, next) => {
    context.Response.Body = new MemoryStream();
    await next();

    // Modify the response here
});

但这只会导致请求永远不会完成 - 它经历了所有管道阶段,但它甚至从未向浏览器返回任何标头。

那么,有什么方法可以修改由StaticFileMiddleware产生的响应?


更新

由于所讨论的 HTML 文件很小(765 字节),因此不必担心内存消耗。 但是,任何读取/修改响应的尝试仍会导致与以前相同的问题(不返回任何内容)。 更明确地说,这是正在做的事情:

app.Use(async (context, next) => {
    var originalStream = context.Response.Body;
    var bufferStream = new MemoryStream();
    context.Response.Body = bufferStream;
    await next();

    bufferStream.Seek(0, SeekOrigin.Begin);

    if (/* some condition */)
    {
        var reader = new StreamReader(bufferStream);
        var response = await reader.ReadToEndAsync();

        // The response string is modified here

        var writer = new StreamWriter(originalStream);
        await writer.WriteAsync(response);
    }
    else
    {
        await bufferStream.CopyToAsync(originalStream);
    }
});

符合else条件的文件返回得很好,但if条件中的特定文件会导致问题。 即使我根本不修改流,它仍然挂起。

是的,提供的默认流是只读的,因为数据只缓冲了一小段时间并刷新到客户端。 因此,您无法倒带或阅读它。

您的第二次尝试不起作用,因为从未处理过原始流。 您完全用MemoryStream替换了响应主体流并丢弃了原始请求,因此永远不会写入任何内容并且客户端永远等待。

您一定不要忘记,客户端的流在原始流中,您不能只是用其他东西替换它。

调用await next()必须MemoryStream读取数据,然后将其写入原始流。

app.Use(async (context, next) => {
    var originalStream = context.Response.Body;
    var memoryStream = new MemoryStream();
    context.Response.Body = memoryStream;
    await next();

    // Here you must read the MemoryStream, modify it, then write the 
    // result into "originalStream"
});

评论

但请注意,此解决方案会将整个响应缓冲到服务器内存中,因此如果您发送大文件,这将显着降低 ASP.NET Core 应用程序的性能,特别是如果您提供几兆字节大小的文件并导致更频繁地触发垃圾收集。

这不仅会影响您的静态文件,还会影响您的所有常规请求,因为 MVC 中间件是在静态文件中间件之后调用的。

如果您真的想在每个请求上修改单个(或文件列表),我宁愿建议您在控制器内执行此操作并将某些文件路由到那里。 请记住,如果静态文件中间件没有找到给定的文件,它将调用链中的下一个文件,直到它到达 mvc 中间件。

只需在那里设置一个匹配特定文件或文件夹的路由并将其路由到控制器。 读取控制器中的文件并将其写入响应流或仅返回新的流(使用return File(stream, contentType);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM