Azure Functions .Net5使用HttpResponseData实现流式响应的异常问题
你遇到的OutOfMemoryException是因为Azure Functions默认会对HttpResponseData的响应内容做全量缓冲,所有写入Body的内容都会先暂存在进程内存中,等全部写入完成后才会一次性发送给客户端,你的循环写入5000万条数据的场景下,内存占用会持续升高直到超出Azure Functions实例的内存上限触发异常。本地开发环境没有严格的内存上限限制所以可以正常运行。
实现流式响应的正确步骤
1. 服务配置
如果使用的是隔离工作进程模型(Isolated Worker),需要先在Program.cs中注入IHttpContextAccessor,用于直接操作原生HTTP响应流:
var host = new HostBuilder() .ConfigureFunctionsWorkerDefaults() .ConfigureServices(services => { services.AddHttpContextAccessor(); }) .Build(); host.Run();
如果是进程内模型(In-Process),不需要额外配置,可以直接从HTTP触发器参数拿到HttpContext,写法和你之前.NET Core 3.1的用法完全一致。
2. 函数代码实现
直接操作原生HttpContext的响应流,绕开默认的缓冲逻辑:
public class StreamOutputFunction { private readonly IHttpContextAccessor _contextAccessor; // 隔离进程模型需要注入,进程内模型可跳过注入直接获取HttpContext public StreamOutputFunction(IHttpContextAccessor contextAccessor) { _contextAccessor = contextAccessor; } [Function("StreamOutput")] public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, "get")] HttpRequestData req) { var httpResponse = _contextAccessor.HttpContext.Response; // 设置响应头 httpResponse.ContentType = "text/plain; charset=utf-8"; httpResponse.Headers.TryAdd("Transfer-Encoding", "chunked"); for (int i = 0; i < 50000000; i++) { await httpResponse.Body.WriteAsync(Encoding.UTF8.GetBytes("Some chunked data\n")); // 主动刷新缓冲区,及时推送内容到客户端 await httpResponse.Body.FlushAsync(); } // 不需要返回HttpResponseData对象,写入完成后请求会自动结束 } }
注意事项
- 不要使用
HttpRequestData.CreateResponse()生成的响应对象,它的Body是缓冲流,无法实现边写边传 - 若传输大文件,可直接调用
sourceStream.CopyToAsync(httpResponse.Body),无需手动循环读写,性能更稳定 - 如果需要设置响应状态码,直接修改
httpResponse.StatusCode即可
内容的提问来源于stack exchange,提问作者Martin Gay
相关产品推荐
相关产品推荐

