首页 > 语言 > JavaScript > 正文

NodeJS使用Range请求实现下载功能的方法示例

2024-05-06 15:28:47
字体:
来源:转载
供稿:网友

前言

本篇使用 NodeJS 的 HTTP 服务创建客户端,使用 Range 请求实现下载功能,并通过本篇的 Demo 扩展在业务中实现断点续传等功能的思路。

服务端的实现

我们通过 http 模块创建服务器处理 Range 请求,在服务器代码中我们为了减少回调嵌套使用 async 函数,所以需要将异步的操作方法转换成 Promise,以往我们使用 util 的 promisify 来一个一个转换异步方法,比较麻烦,我们这次使用第三方模块 mz 并直接引入转换好的替代模块。

使用 mz 之前需要先安装:

npm install mz

服务端代码如下:

// 文件:server.jsconst http = require("http");const path = require("path");const url = require("url");// 引入 mz 模块转换成 Promise 的 fs 模块const fs = require("mz/fs");// 请求处理函数async function listener(req, res) {  // 获取 range 请求头,格式为 Range:bytes=0-5  let range = req.headers["range"];  // 下载文件路径  let p = path.resovle(__dirname, url.parse(url, true).pathname);  // 存在 range 请求头将返回范围请求的数据  if (range) {    // 获取范围请求的开始和结束位置    let [, start, end] = range.match(/(/d*)-(/d*)/);    // 错误处理    try {      let statObj = await fs.stat(p);    } catch (e) {      res.end("Not Found");    }    // 文件总字节数    let total = statObj.size;    // 处理请求头中范围参数不传的问题    start = start ? ParseInt(start) : 0;    end = end ? ParseInt(end) : total - 1;    // 响应客户端    res.statusCode = 206;    res.setHeader("Accept-Ranges", "bytes");    res.setHeader("Content-Range", `bytes ${start}-${end}/${total}`);    fs.createReadStream(p, { start, end }).pipe(res);  } else {    // 没有 range 请求头时将整个文件内容返回给客户端    fs.createReadStream(p).pipe(res);  }}// 创建服务器const server = http.createServer(listener);// 监听端口server.listen(3000, () => {  console.log("server start 3000");});

在上面服务端的代码中,需要兼容 Range 请求和普通请求,两种请求的区别是,如果客户端发送的是 Range 请求,会携带 Range:bytes=0-5 格式的请求头,我们可以通过 req 的 headers 属性获取,在获取请求头时,原本大写字母开头 NodeJS 统一处理成小写,所以获取时应小写。

如果是 Range 请求则通过可读流读取对应的内容返回客户端,如果不是,则通过可读流读取整个文件返回客户端,在响应 Range 请求的过程中需要设置响应状态为 206,需要设置响应头 Accept-Ranges 值为 bytes,需要设置响应头 Content-Range 值为 byte 0-5/100 的格式,0 为返回数据开始的索引,5 为结束的索引(包含),100 为文件的总字节数。

在通过 url 和 path 模块解析和拼接下载文件路径时,应该进行错误检测,如果文件不存在则直接返回客户端 Not Found。

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表

图片精选