在C#的ASP.NET应用中读取multipart/x-mixed-replace类型的HttpWebResponse
处理ASP.NET中multipart/x-mixed-replace类型的视频流响应
嘿,这个问题我太熟了!你之前用StreamReader.ReadToEnd()肯定行不通,因为multipart/x-mixed-replace这种响应根本不是一次性的文本流——它是分块持续传输的,专门用来推送实时更新的内容(比如视频帧、连续截图这类),流会一直保持打开直到连接断开。直接读“到结尾”自然拿不到正确内容,甚至会一直阻塞等待流结束。
下面给你两种可行的解决方案,按需选择:
方案1:直接转发流给前端(最简单,推荐)
如果你的需求是把这个视频流展示给前端页面,其实不需要自己解析分块,直接把服务器返回的流转发给浏览器就行——浏览器本身支持解析multipart/x-mixed-replace格式:
// 假设你已经创建好HttpWebRequest并获取到response HttpWebResponse response = (HttpWebResponse)request.GetResponse(); // 把响应头原样传给前端,让浏览器识别类型 Response.ContentType = response.ContentType; if (!string.IsNullOrEmpty(response.Headers["Content-Disposition"])) { Response.AddHeader("Content-Disposition", response.Headers["Content-Disposition"]); } // 直接将源流复制到输出流,边读边传 using (Stream sourceStream = response.GetResponseStream()) { sourceStream.CopyTo(Response.OutputStream); Response.Flush(); }
这样浏览器会自动处理分块,实时渲染视频流内容,不需要你手动解析边界和分块。
方案2:手动解析分块(需要处理每帧数据时用)
如果需要对每一块视频数据做自定义处理(比如存本地、修改帧内容),就得手动解析边界和分块:
步骤1:读取流并查找边界
首先用二进制流读取,因为视频是二进制数据,不能用文本阅读器。然后循环查找指定的边界--myboundary,拆分出每个数据块:
HttpWebResponse response = (HttpWebResponse)request.GetResponse(); using (Stream responseStream = response.GetResponseStream()) { byte[] boundaryBytes = Encoding.ASCII.GetBytes("--myboundary"); byte[] buffer = new byte[4096]; int bytesRead; List<byte> currentChunkBuffer = new List<byte>(); while ((bytesRead = responseStream.Read(buffer, 0, buffer.Length)) > 0) { // 将读取的字节加入临时缓冲区 currentChunkBuffer.AddRange(buffer.Take(bytesRead)); // 检查缓冲区中是否包含边界 int boundaryPos = FindByteSequence(currentChunkBuffer.ToArray(), boundaryBytes); if (boundaryPos != -1) { // 提取边界前的完整数据块 byte[] fullChunk = currentChunkBuffer.Take(boundaryPos).ToArray(); // 处理这个数据块(比如解析头、提取视频帧) ProcessVideoChunk(fullChunk); // 移除已处理的内容(包括边界) currentChunkBuffer.RemoveRange(0, boundaryPos + boundaryBytes.Length); } } }
步骤2:实现字节序列查找方法
上面用到的FindByteSequence用来在字节数组中定位边界,实现如下:
private static int FindByteSequence(byte[] source, byte[] target) { if (target.Length == 0 || source.Length < target.Length) return -1; for (int i = 0; i <= source.Length - target.Length; i++) { bool isMatch = true; for (int j = 0; j < target.Length; j++) { if (source[i + j] != target[j]) { isMatch = false; break; } } if (isMatch) return i; } return -1; }
步骤3:解析数据块的内容
每个分块开头通常带HTTP头(比如Content-Type、Content-Length),你需要先拆分出头和实际的视频数据:
private static void ProcessVideoChunk(byte[] chunkData) { // 找到头和数据的分隔线:\r\n\r\n byte[] separator = Encoding.ASCII.GetBytes("\r\n\r\n"); int separatorPos = FindByteSequence(chunkData, separator); if (separatorPos != -1) { // 解析头信息(可选,如果你需要知道内容类型等) string headerText = Encoding.ASCII.GetString(chunkData.Take(separatorPos).ToArray()); // 比如提取Content-Length: // int contentLength = int.Parse(Regex.Match(headerText, @"Content-Length: (\d+)").Groups[1].Value); // 提取实际的视频二进制数据 byte[] videoFrameData = chunkData.Skip(separatorPos + separator.Length).ToArray(); // 这里做你的自定义处理:比如写入文件、转码等 // File.WriteAllBytes($"frame_{DateTime.Now.Ticks}.jpg", videoFrameData); } }
关键提醒
multipart/x-mixed-replace是长连接流,循环会一直运行直到源流关闭(比如视频流结束、连接断开),所以要注意异常处理(比如网络中断时的捕获)。- 不要用
StreamReader处理二进制流,会导致数据损坏(因为文本编码会修改二进制字节)。
内容的提问来源于stack exchange,提问作者PraveenK
相关产品推荐
相关产品推荐

