You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

调用返回流式文本的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 04:17:46