.NET 6 Blazor WASM基于IAsyncEnumerable的HTTP文本流无缓冲处理问题
根因分析
- Blazor WebAssembly的HttpClient底层基于浏览器Fetch API实现,默认会对响应体做全量缓冲,就算设置了
HttpCompletionOption.ResponseHeadersRead也不会生效。 - System.Text.Json默认的异步反序列化缓冲区大小为16KB,会攒够数据才开始解析,小体积的流式响应会被延迟处理。
修复步骤
第一步:服务端补充配置(避免服务端侧缓冲)
先确保服务端本身没有对响应做缓冲,修改API代码如下:
using Microsoft.AspNetCore.Http.Features; [HttpGet("lines")] public async IAsyncEnumerable<string> GetLines() { // 禁用服务端响应缓冲 Response.Headers.CacheControl = "no-cache"; Response.ContentType = "application/json; charset=utf-8"; HttpContext.Features.Get<IHttpResponseBodyFeature>()?.DisableBuffering(); for (var i = 0; i < 10; ++i) { yield return "test"; await Task.Delay(1000); } }
第二步:客户端代码修改
首先引入Blazor WASM专属的HTTP扩展命名空间,开启浏览器侧的流式响应支持,同时缩小JSON反序列化的缓冲区:
using Microsoft.AspNetCore.Components.WebAssembly.Http; using System.Text.Json; public async IAsyncEnumerable<string?> GetLines() { var request = new HttpRequestMessage(HttpMethod.Get, $"{apiRoot}/lines"); // 关键:开启浏览器Fetch API的流式响应支持,禁用缓冲 request.SetBrowserResponseStreamingEnabled(true); var response = await HttpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead); if (response.IsSuccessStatusCode) { var responseStream = await response.Content.ReadAsStreamAsync(); // 配置JSON序列化器使用最小缓冲区 var jsonOptions = new JsonSerializerOptions { DefaultBufferSize = 64, PropertyNameCaseInsensitive = true }; await foreach (var line in JsonSerializer.DeserializeAsyncEnumerable<string>(responseStream, jsonOptions)) { yield return line; } } else { Log.Error($"Server response code: {response.StatusCode}"); yield return null; } }
可选优化(纯文本场景)
如果你的业务场景只需要传输纯文本换行分隔内容,不需要JSON序列化,可以直接用StreamReader逐行读取,延迟更低:
// 替换JSON反序列化部分即可 using var reader = new StreamReader(responseStream); while (!reader.EndOfStream) { var line = await reader.ReadLineAsync(); yield return line; }
内容的提问来源于stack exchange,提问作者Frank
相关产品推荐
相关产品推荐

