调用返回流式文本的Azure Function时出现ERR_INCOMPLETE_CHUNKED_ENCODING错误
解决流式API的
ERR_INCOMPLETE_CHUNKED_ENCODING及Blazor客户端消费问题 问题背景
调用返回文本流的API端点时出现以下异常场景:
- 直接在浏览器地址栏访问端点,能正常流式返回内容,但浏览器控制台抛出
ERR_INCOMPLETE_CHUNKED_ENCODING错误 - Blazor客户端调用该端点时,循环读取流的代码触发错误;网络面板显示预飞OPTIONS请求和GET请求均返回200 OK,但开发者工具中响应内容为空
服务端为.NET 6 Azure Function,以下是错误原因分析、排查步骤及最终解决代码。
1. 错误的可能原因
- 分块编码未正确终止:流式响应采用HTTP分块传输编码时,服务端未发送终止块(
0\r\n\r\n),浏览器判定响应不完整,抛出ERR_INCOMPLETE_CHUNKED_ENCODING - Azure Functions默认响应机制不兼容流式场景:.NET 6 Azure Functions的默认响应处理逻辑未适配流式输出,未正确管理响应流的生命周期
- CORS配置缺失关键头:虽然预飞请求返回200,但未配置
Access-Control-Expose-Headers: Transfer-Encoding,导致Blazor客户端无法识别分块编码的响应元数据 - 客户端流读取逻辑问题:Blazor客户端读取流时同步、异步操作混用,导致流读取过程意外中断
2. 排查步骤
- 验证分块编码完整性:用curl或Postman调用端点,查看原始响应内容,确认末尾是否包含终止块
0\r\n\r\n。示例curl命令:curl -v https://your-function-endpoint - 检查Azure Functions执行日志:在Azure门户查看Function的运行日志,确认响应流是否被正确关闭,是否存在未捕获的异常
- 调试客户端流读取逻辑:在Blazor的流读取循环中添加日志,记录每次读取的字节数、流的状态(是否已结束),排查是否在读取过程中流被意外关闭
- 测试极简流式端点:编写仅返回固定分块内容的Azure Function,验证是否能被Blazor正常消费,逐步定位是否为业务代码导致的问题
- 核对CORS响应头:确认服务端返回的CORS头包含
Access-Control-Expose-Headers: Transfer-Encoding,确保客户端能识别分块编码
3. 最终解决代码(服务端)
核心是通过IHttpResponseBodyFeature直接控制响应流,并调用CompleteAsync确保分块编码正确终止:
using Microsoft.AspNetCore.Http; using Microsoft.Azure.WebJobs; using Microsoft.Azure.WebJobs.Extensions.Http; using Microsoft.Extensions.Logging; using System.IO; using System.Text; using System.Threading.Tasks; namespace StreamFunction { public static class StreamEndpoint { [FunctionName("StreamEndpoint")] public static async Task Run( [HttpTrigger(AuthorizationLevel.Anonymous, "get", "options", Route = null)] HttpRequest req, ILogger log) { // 处理OPTIONS预飞请求 if (req.Method == HttpMethods.Options) { req.HttpContext.Response.Headers.Add("Access-Control-Allow-Origin", "*"); req.HttpContext.Response.Headers.Add("Access-Control-Allow-Headers", "*"); req.HttpContext.Response.Headers.Add("Access-Control-Allow-Methods", "GET, OPTIONS"); return; } req.HttpContext.Response.Headers.Add("Access-Control-Allow-Origin", "*"); req.HttpContext.Response.ContentType = "text/plain"; req.HttpContext.Response.Headers.Add("Transfer-Encoding", "chunked"); // 获取响应体特性直接操作流 var responseBodyFeature = req.HttpContext.Features.Get<IHttpResponseBodyFeature>(); using var writer = new StreamWriter(responseBodyFeature.Stream, Encoding.UTF8); // 模拟流式输出内容 for (int i = 0; i < 10; i++) { await writer.WriteLineAsync($"Stream content line {i}"); await writer.FlushAsync(); await Task.Delay(500); } // 确保分块编码正确终止 await responseBodyFeature.CompleteAsync(); } } }
Blazor客户端调用示例(异步读取流)
using System.Net.Http; using System.Text; public async Task ConsumeStreamAsync() { using var client = new HttpClient(); using var response = await client.GetStreamAsync("https://your-function-endpoint"); using var reader = new StreamReader(response, Encoding.UTF8); while (!reader.EndOfStream) { var line = await reader.ReadLineAsync(); // 处理流式内容 Console.WriteLine(line); } }
内容的提问来源于stack exchange,提问作者Niels Brinch
相关产品推荐
相关产品推荐

