Node.js视频流异常:Expo跨端播放MongoDB GFS视频失败排查
问题排查与修复方案
错误码解析
NSURLErrorDomain -1005 表示网络连接被意外中断,本质是iOS的AVPlayer判定服务端响应不符合HTTP规范,主动终止了连接。结合你提到的「自有视频失效但测试视频正常」,问题大概率出在Range请求的边界处理、GFS文件读取逻辑或HTTP响应头的合规性上。
排查步骤
- 验证自有视频文件完整性:直接从GFS下载自有视频到本地,确认文件能正常播放,排除文件损坏或上传不完整的问题。
- 检查服务端Range请求的边界校验:客户端可能发送非法Range(比如
bytes=1000000-但文件实际只有500000字节),未做校验会导致GFS读取流出错,进而引发连接中断。 - 校验HTTP响应头的合规性:iOS对HTTP头格式要求严格,比如
Content-Range必须严格遵循bytes start-end/total格式,Content-Length必须和实际返回字节数完全匹配。 - 排查非Range请求的兼容性:Web和Android失效可能是因为非Range请求的响应头缺失或错误,比如未正确设置
Accept-Ranges,或Content-Length与实际返回字节不符。
代码修复建议
服务端Node.js代码修正
重点补充Range边界校验、完善错误处理、优化响应头设置:
if (req.headers['range']) { const range = req.headers.range; const total = file.length; // 解析Range并做合法性校验 const positions = range.replace(/bytes=/, "").split("-"); let start = Number(positions[0]); let end = positions[1] ? Number(positions[1]) : total - 1; // 修正非法的Range值 start = Math.max(0, Math.min(start, total - 1)); end = Math.max(start, Math.min(end, total - 1)); const chunksize = end - start + 1; const header = { "Content-Range": `bytes ${start}-${end}/${total}`, "Accept-Ranges": "bytes", "Content-Length": chunksize, "Content-Type": file.contentType }; // 先确认GFS能正常读取再发送响应头 try { const readstream = gfs.gridfsBucket.openDownloadStream(file._id, { start, end }); res.writeHead(206, header); readstream.on("error", (err) => { console.error(err); // 响应头已发送,只能终止连接 res.end(); }); readstream.pipe(res); } catch (err) { console.error(err); res.status(400).json({ err: "Invalid range request" }); } } else { const readstream = gfs.gridfsBucket.openDownloadStream(file._id); res.set({ "Content-Type": file.contentType, "Content-Length": file.length, "Accept-Ranges": "bytes" // 告知客户端支持分段下载 }); readstream.on("error", (err) => { console.error(err); // 未发送响应头时可以返回错误 if (!res.headersSent) { res.status(404).json({ err: "Error reading file" }); } else { res.end(); } }); readstream.pipe(res); }
关键修正点说明
- Range边界校验:确保
start和end始终在合法范围内,避免GFS读取超出文件长度的内容。 - 错误处理优化:区分响应头是否已发送的情况,避免重复发送响应头导致服务端错误。
- 补充
Accept-Ranges头:非Range请求也返回该头,让客户端明确知道服务端支持分段下载,减少iOS的异常请求。 - 模板字符串优化:避免字符串拼接可能带来的格式错误。
Expo端补充检查
- 确认
tempVideo.url是直接指向服务端视频接口的完整URL,没有重定向或签名过期问题。 - 测试时开启iOS模拟器的网络调试(Safari开发者工具→模拟器→网络面板),查看所有视频请求的响应状态码和头信息,确认Range请求的响应是否符合206 Partial Content规范。
内容的提问来源于stack exchange,提问作者Bogzzz
相关产品推荐
相关产品推荐

