使用 node 实现前后端分段下载文件

2024-04-07 10:49:47

阅读:992
分类:代码段
标签:nodejs

使用 node 实现前后端分段下载文件

实现前后端分段下载文件,一般称为分片下载或断点续传。这样的功能可以帮助在网络不稳定或下载较大文件时提供更好的用户体验。前端会将文件分成多个片段,然后逐个片段地请求后端,并在后端将这些片段组合成完整的文件

  1. 前端部分(HTML 和 JavaScript)
<!DOCTYPE html>
<html>
  <head>
    <title>分段下载文件示例</title>
  </head>
  <body>
    <button onclick="downloadFile()">下载文件</button>
    <script>
      async function downloadFile() {
        const url = "/download"; // 后端提供的下载接口
        const fileName = "example.txt"; // 下载的文件名

        const response = await fetch(url);
        const fileSize = response.headers.get("content-length");
        const chunkSize = 1024 * 1024; // 每个片段大小为1MB

        let downloaded = 0;
        const fileStream = new ReadableStream({
          start(controller) {
            controller.enqueue(new TextEncoder().encode(""));
          },
        });

        while (downloaded < fileSize) {
          const from = downloaded;
          const to = Math.min(from + chunkSize, fileSize) - 1;

          const headers = new Headers();
          headers.append("Range", `bytes=${from}-${to}`);

          const chunkResponse = await fetch(url, { headers });
          const chunk = await chunkResponse.blob();

          fileStream.getWriter().write(chunk);
          downloaded += chunk.size;
        }

        const downloadStream = new WritableStream({
          write(chunk) {
            const url = URL.createObjectURL(chunk);
            const a = document.createElement("a");
            a.href = url;
            a.download = fileName;
            a.click();
            URL.revokeObjectURL(url);
          },
        });

        await fileStream.pipeTo(downloadStream);
      }
    </script>
  </body>
</html>
  1. 后端部分(Node.js 使用 Express 框架)
// server.js
const express = require("express");
const fs = require("fs");

const app = express();
const filePath = "./example.txt"; // 要下载的文件路径

app.get("/download", (req, res) => {
  const stat = fs.statSync(filePath);
  const fileSize = stat.size;
  const range = req.headers.range;

  if (range) {
    const parts = range.replace(/bytes=/, "").split("-");
    const start = parseInt(parts[0], 10);
    const end = parts[1] ? parseInt(parts[1], 10) : fileSize - 1;

    const chunkSize = end - start + 1;
    const file = fs.createReadStream(filePath, { start, end });
    const headers = {
      "Content-Range": `bytes ${start}-${end}/${fileSize}`,
      "Accept-Ranges": "bytes",
      "Content-Length": chunkSize,
      "Content-Type": "application/octet-stream",
    };

    res.writeHead(206, headers);
    file.pipe(res);
  } else {
    const headers = {
      "Content-Length": fileSize,
      "Content-Type": "application/octet-stream",
    };
    res.writeHead(200, headers);
    fs.createReadStream(filePath).pipe(res);
  }
});

const PORT = 3000;
app.listen(PORT, () => {
  console.log(`Server started on port ${PORT}`);
});

以上就是node实现的文件分段下载,那么如何实现断点续传呢?
其实只需要我们在前端使用一个全局变量downloaded来记录已经下载的字节数,然后在每次下载请求时,在请求的header中添加Range字段,指定从downloaded位置开始下载就实现了断点续传的功能

评论:

    X

    备案号 皖ICP备19021899号-1  技术支持 © 947968273@qq.com