在ASP.NET Core中修改静态文件响应 [英] Modify static file response in ASP.NET Core

查看:172
本文介绍了在ASP.NET Core中修改静态文件响应的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I serve a bunch of static files in my app with app.UseStaticFiles(). I'd like to inject some additional markup into the response for a particular HTML file before it's sent. My first attempt was to add middleware like this before the static files middleware:

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

    // Modify the response here
});

但是,这不起作用,因为我实际上无法读取读取的响应流-它在后台使用Kestrel的FrameResponseStream,这是不可读的.

However, this doesn't work as I can't actually read the read the response stream - it's using Kestrel's FrameResponseStream under the hood, which is unreadable.

因此,我想可以将响应正文流替换为可以写入的MemoryStream:

So, I figured I could replace the response body stream with a MemoryStream that I could write to:

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

    // Modify the response here
});

但这只会导致请求永不完成-它经历了所有流水线阶段,但从未向浏览器返回任何标头.

But this just causes the request to never complete - it goes through all the pipeline stages, but it never even returns any headers to the browser.

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

So, is there any way I can modify the response that is produced by the StaticFileMiddleware?

更新

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

As the HTML file in question is tiny (765 bytes), memory consumption isn't a concern. However, any attempts to read/modify the response still causes the same problem as before (nothing is returned). More explicitly, here's what's being done:

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条件下的特定文件会造成麻烦.即使我根本不修改流,它仍然挂起.

The files hitting the else condition are returned just fine, but the particular file in the if condition causes trouble. Even if I don't modify the stream at all, it still hangs.

推荐答案

是的,提供的默认流是只读的,因为数据仅在短时间内被缓冲并刷新到客户端.因此,您不能倒带或阅读它.

Yes, the default stream provided is read only because the data is only buffered for a short moment and flushed to the client. Hence you can't rewind or read it.

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

Your second attempt doesn't work because the original stream is never processed. You replaced the response body stream entirely with MemoryStream and thrown away the original request, so there is never something written to it and the client waits forever.

您一定不要忘记,到客户端的流在原始流之内,您不能仅仅将其替换为其他内容.

You must not forget, that the stream to the client is within the original stream, you can't just replace it with something else.

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

After calling await next() you must read the data from the MemoryStream and then write it to the original stream.

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应用程序的性能,尤其是当您提供大小为几兆字节的文件,并导致更频繁地触发垃圾回收.

Remark

But be aware, that this solution will buffer the whole response into the servers memory, so if you send large files this will significantly degenerate the performance of your ASP.NET Core application, especially if you serve files which are several megabytes in size and cause the garbage collection to be triggered more often.

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

And this wouldn't only affect your static files, but also all your regular requests, because the MVC Middleware is called after the static files middleware.

如果您真的想在每个请求上修改单个(或文件列表),我建议您在控制器内执行此操作,然后在其中路由某些文件.请记住,如果静态文件中间件找不到给定的文件,它将调用链中的下一个,直到涉及到mvc中间件.

If you really want to modify a single (or a list of files) on each request, I'd rather suggest you doing this inside a controller and route certain files there. Remember, if the given file is not found by the static files middleware, it will call the next one in chain until it comes to the mvc middleware.

只需在此处设置与特定文件或文件夹匹配的路由,然后将其路由到控制器即可.在控制器中读取文件并将其写入响应流,或者只是返回新的流(使用return File(stream, contentType);

Just setup a route there that will match a specific file or folder and route it to a controller. Read the file in the controller and write it to the response stream or just return the new steam (using return File(stream, contentType);

这篇关于在ASP.NET Core中修改静态文件响应的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆