Skip to content

前后端大文件分片上传调研-express-fileupload

一、如何获取代码

https://gitee.com/fe521/nodejs-fileupload-sample

二、接口文档

服务器地址: http://localhost:8001

1. 文件上传

请求 URL:

  • http://xx.com/api/upload

请求方式:

  • POST

请求类型:

  • multipart/form-data

参数:

参数名必选类型说明
sampleFilefile文件块
currentChunkint当前文件块序号
totalChunksint文件总块数

返回示例

json
{
  "code": 200,
  "message": "success",
  "data": {
    "uploaded": true
  }
}
json
{
  "code": 400,
  "message": "No files were uploaded.",
  "data": {
    "uploaded": false
  }
}

返回参数说明:

参数名类型说明
codeint状态码
messagestring返回信息
dataObject返回的数据

备注

  • 更多返回错误代码请看首页的错误代码描述
  • 文件分块上传,前端会将文件分割成多个块,每个块单独发送一个请求,服务器端需要支持处理多个请求并合并文件。

2. 文件块合并

请求 URL:

  • http://xx.com/api/merge

请求方式:

  • POST

请求类型:

  • application/json

参数:

参数名必选类型说明
fileNamestring文件名
totalChunksint文件总块数

返回示例

json
{
  "code": 200,
  "message": "success",
  "data": {
    "merged": true
  }
}

返回参数说明:

参数名类型说明
codeint状态码
messagestring返回信息
dataObject返回的数据

备注

  • 更多返回错误代码请看首页的错误代码描述
  • 当所有文件块上传完成后,前端会调用此接口进行文件块的合并。

根据你提供的代码,以下是对应的三个后端接口的文档 Markdown 模板:

3. 获取文件列表

请求 URL:

  • http://xx.com/api/filelist

请求方式:

  • GET

返回示例

json
{
  "code": 200,
  "type": "success",
  "data": {
    "totalFiles": 100,
    "page": 1,
    "limit": 10,
    "files": ["file1", "file2", "file3"]
  }
}

返回参数说明:

参数名类型说明
codeint状态码
typestring响应类型,成功为 "success"
dataObject返回的数据,包含一个文件名数组
data.totalFilesObject返回的数据,包含一个文件名数组
data.pageint当前页
data.limitint每一条数
data.filesArray文件名称列表

备注

  • 更多返回错误代码请看首页的错误代码描述

4. 文件下载

请求 URL:

  • http://xx.com/api/download/{fileName}

请求方式:

  • GET

URL 参数:

参数名必选类型说明
fileNamestring文件名

返回:

  • 文件的二进制流

备注

  • 更多返回错误代码请看首页的错误代码描述

5. 删除文件

请求 URL:

  • http://xx.com/api/delete/{fileName}

请求方式:

  • DELETE

URL 参数:

参数名必选类型说明
fileNamestring文件名

返回示例

json
{
  "code": 200,
  "message": "success",
  "data": {
    "deleted": true
  }
}

返回参数说明:

参数名类型说明
codeint状态码
messagestring返回信息
dataObject返回的数据

备注

  • 更多返回错误代码请看首页的错误代码描述

三、实现步骤

1. 打开 express-fileupload 开源仓库地址

https://www.npmjs.com/package/express-fileupload

2. 进入到 GitHub 页面

https://github.com/richardgirges/express-fileupload#readme

3. 点击 Download 按钮 下载开源库

https://github.com/richardgirges/express-fileupload/archive/refs/heads/master.zip

4. 本地创建项目目录

bash
mkdir -p nodejs-fileupload-sample

5. 创建 package.json

bash
# node 版本,如果没有node,先安装node
node -v
v18.15.0
bash
npm init -y

6. 把下载 express-fileupload 的 zip 包解压,并拷贝 example 目录到当前项目的根目录

此时 nodejs-fileupload-sample/目录下应该有

server.js
index.html

7. 修改 server.js 中的内容

修改前

js
const express = require("express");
const fileUpload = require("../lib/index");
const app = express();

修改后

js
const express = require("express");
const fileUpload = require("express-fileupload");
const app = express();

8. 安装 express、express-fileupload 和 nodemon

bash
npm install express express-fileupload nodemon

9. 修改 package.json "scripts" 启动项目

json
  "scripts": {
    "start": "nodemon server.js"
  },

10. 启动项目后端文件上传项目

bash
npm start

此时已经实现了文件上传功能,访问端口 http://localhost:8000/form 可以看到 index.html 内容

11. 初始化代码仓库并提交代码

bash
git init
bash
git add .
bash
git commit -m 'feat: '

12. 打开码云-创建一个仓库-名称为 nodejs-fileupload-sample

13. 拷贝 remote 命令 git@gitee.com:fe521 部分修改成你们自己的

注意:使用 ssh 的方式

bash
git remote add origin git@gitee.com:fe521/nodejs-fileupload-sample.git

检查是否添加成功,出现下面状态时成功的

powershell
PS D:\dev\file-upload-sample> git remote -v
origin  git@gitee.com:fe521/nodejs-fileupload-sample.git (fetch)
origin  git@gitee.com:fe521/nodejs-fileupload-sample.git (push)

14. 在本地提交代码

powershell
PS D:\dev\file-upload-sample> git push
fatal: The current branch main has no upstream branch.
To push the current branch and set the remote as upstream, use

    git push --set-upstream origin main

To have this happen automatically for branches without a tracking
upstream, see 'push.autoSetupRemote' in 'git help config'.

拷贝命令,终端中输入

powershell
git push --set-upstream origin main

完成提交代码

15. 更多内容看视频

视频在 “李钟意讲前端” 抖音店铺课程 - “web 全栈”

四、常见问题

1. 上传文件-中文名称乱码

解决方案如下

js
app.use(
  fileUpload({
    // 解决中文乱码:https://www.jianshu.com/p/813d85daaf60
    createParentPath: true,
    defParamCharset: "utf8", // 添加utf8编码

    limits: { fileSize: 5 * 1024 * 1024 }, // 5M (上传大于次大小会自动截取掉)
    useTempFiles: true, // 使用临时模板目录
    tempFileDir: path.resolve(__dirname, "./uploads-tmp/"),
  })
);

2. (node:18784) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 finish listeners added to [WriteStream]. Use emitter.setMaxListeners()

遇到这个问题,通过 async 模块 实现并发限制

bash
npm i async
js
async.eachLimit(
  chunkIndices,
  8,
  function (chunkIndex, done) {
    const readStream = fs.createReadStream(`${uploadPath}_temp_${chunkIndex}`);
    readStream.pipe(writeStream, { end: false });
    readStream.on("end", function () {
      mergedChunks++;
      if (mergedChunks === totalChunks) {
        writeStream.end();
      }
      done();
    });
    readStream.on("error", function (err) {
      writeStream.end();
      callback(err);
    });
  },
  function (err) {
    if (err) {
      console.error("Error", err);
      callback(err);
    } else {
      callback(err);
    }
  }
);