ASP.NET Core转发AXIS摄像头multipart/x-mixed-replace流HttpClient阻塞求助
问题根因
你遇到的阻塞问题由两个核心错误共同导致:
- Blazor客户端的
HttpClient默认GetStreamAsync方法实际使用HttpCompletionOption.ResponseContentRead行为,会等待完整响应加载完成才返回Task。但MJPG是无限长的实时流,永远不会加载完成,因此Task永远不会进入完成状态,代码就卡在await处。 - 你读取JPEG帧的逻辑错误,使用文本读取器
StreamReader读取二进制JPEG数据,会导致数据损坏,就算过了GetStreamAsync的步骤也无法正常渲染图片。
修复步骤
第一步:替换GetStreamAsync为SendAsync,指定仅读取响应头就返回
手动构造请求,指定HttpCompletionOption.ResponseHeadersRead,强制HttpClient在读取完响应头后立刻返回,不缓冲响应正文:
private async void StartStreamingRequest(object sender, ElapsedEventArgs e) { Console.WriteLine("I'm about to request live stream"); // 手动构造请求,指定响应头读取完成就结束等待 using var request = new HttpRequestMessage(HttpMethod.Get, "CameraSystem/getStream"); var response = await Http.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, _cancellationTokenSource.Token); // 校验响应状态 response.EnsureSuccessStatusCode(); Stream responseStream = await response.Content.ReadAsStreamAsync(_cancellationTokenSource.Token); Console.WriteLine("Header found!"); string boundary = "myboundary"; var streamReader = new MultipartReader(boundary, responseStream); try { while (!_cancellationTokenSource.Token.IsCancellationRequested) { MultipartSection nextFrame = await streamReader.ReadNextSectionAsync(_cancellationTokenSource.Token); if (nextFrame == null) break; // 流断开时退出循环 await DisplayOneFrameCallback(nextFrame.Body); } } catch (OperationCanceledException) { // 取消请求属于正常操作,无需额外处理 } }
第二步:修复JPEG帧读取逻辑,正确处理二进制数据
StreamReader是专门用于读取文本编码的工具,直接读取二进制JPEG数据会导致字节转码错误,必须直接读取字节数组再转base64:
private async Task DisplayOneFrameCallback(Stream body) { // 直接读取二进制流为字节数组 using var ms = new MemoryStream(); await body.CopyToAsync(ms, _cancellationTokenSource.Token); byte[] frameBytes = ms.ToArray(); _imgSrc = "data:image/jpeg;base64," + Convert.ToBase64String(frameBytes); StateHasChanged(); }
额外优化建议
- 不要用Timer的Elapsed事件触发流请求,若Timer间隔小于流启动时间,会重复发起大量无效请求,建议仅在页面初始化时发起一次流请求即可。
- 页面销毁时需调用
_cancellationTokenSource.Cancel()主动释放流资源,避免内存泄漏。
内容的提问来源于stack exchange,提问作者Alessandro Martinelli
相关产品推荐
相关产品推荐

