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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 01:52:13