基于Node.js的大文件分片上传示例

下面是“基于Node.js的大文件分片上传示例”的完整攻略及两条示例说明。

简介

当上传大文件时,可能会遇到一些问题,例如网络不稳定、上传时间长等。大量数据上传时,还需要使用分片上传技术,避免将整个文件发送到服务器。在这里,我们将介绍如何使用Node.js实现大文件分片上传。

实现步骤

安装依赖

首先,我们需要先安装依赖包,这里我们使用multipartyformidable来处理上传的表单。

npm install multiparty formidable --save

实现服务端代码

我们可以通过以下代码来实现服务端的功能:

const http = require('http');
const url = require('url');
const fs = require('fs');
const { parse } = require('querystring');
const formidable = require('formidable');

http.createServer((req, res) => {
  const { pathname } = url.parse(req.url);

  if (pathname === '/') {
    if (req.method === 'GET') { // 获取页面
      fs.readFile('./index.html', (err, data) => {
        res.end(data);
      });
    } else if (req.method === 'POST') { // 上传文件
      const form = new formidable.IncomingForm();
      form.parse(req, (err, fields, files) => {
        if (err) throw err;
        console.log(fields); // 输出表单中传递的其他参数
        console.log(files); // 文件的相关信息,包括路径、大小等
        res.end('upload success!');
      });
    }
  } else { // 处理其他请求
    res.statusCode = 404;
    res.end('not found');
  }
}).listen(3000, () => {
  console.log('server is running at http://localhost:3000');
});

该服务端代码实现了获取首页和上传文件的功能,我们使用formidable中的IncomingForm实例来处理上传的表单数据,具体的文件上传过程将在下面的示例中介绍。

实现客户端代码

在客户端页面中,需要使用JavaScript来实现文件上传功能:

<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <title>大文件分片上传示例</title>
</head>

<body>
  <h1>大文件分片上传示例</h1>
  <form id="uploadForm" method="post" enctype="multipart/form-data">
    <input type="text" name="name" placeholder="请输入名字"><br>
    <input type="file" name="file"><br>
    <button type="submit">上传</button>
  </form>
  <script>
    const form = document.getElementById('uploadForm');
    form.addEventListener('submit', (event) => {
      event.preventDefault();

      // 获取需要上传的文件
      const file = form.elements['file'].files[0];
      console.log(file);

      // 分片上传代码在这里实现
    });
  </script>
</body>

</html>

在这里,我们使用了HTML5新增的FormData API来实现文件上传,上传的文件会包装在FormData对象中,然后通过ajax提交到服务器。

示例

示例一:上传文件到七牛云

在这个示例中,我们将使用qiniu库,将文件上传到七牛云存储中。

const qiniu = require('qiniu');
const path = require('path');
const { accessKey, secretKey, bucket, domain } = require('./config');

const mac = new qiniu.auth.digest.Mac(accessKey, secretKey);
const options = {
  scope: bucket,
};
const putPolicy = new qiniu.rs.PutPolicy(options);
const uploadToken = putPolicy.uploadToken(mac);
const config = new qiniu.conf.Config();
const formUploader = new qiniu.form_up.FormUploader(config);

function uploadChunk(fileKey, localFile, uploadId, chunkSize, chunkNum, offset, progressCallback) {
  return new Promise((resolve, reject) => {
    const putExtra = new qiniu.form_up.PutExtra();
    putExtra.progressCallback = progressCallback;

    formUploader.putFile(uploadToken, fileKey, localFile, putExtra, (err, _, info) => {
      if (err) {
        reject(err);
        return;
      }

      if (info.statusCode === 200) {
        console.log(`Part ${chunkNum} uploaded successfully.`);
        const uploadedChunkInfo = { 
          etag: info.etag,
          partNumber: chunkNum,
        };
        resolve(uploadedChunkInfo);
      } else {
        reject(info);
      }
    });
  });
}

function uploadFile(localFile, fileKey) {
  return new Promise((resolve, reject) => {
    qiniu.rpc.uploadId(mac, bucket, fileKey).then(uploadId => {
      const filesize = getFilesizeSync(localFile);
      const chunkSize = filesize < chunkSizeLimit ? filesize : chunkSizeLimit;
      const chunkNum = Math.ceil(filesize / chunkSize);

      // 分片上传代码
      const promises = Array(chunkNum).fill().map((_, index) => {
        const start = index * chunkSize;
        const end = (index + 1) * chunkSize - 1 > filesize ? filesize : (index + 1) * chunkSize;
        const offset = start;

        const chunkFile = path.resolve(chunkDir, `${fileKey}.${uploadId}.${index}`);
        return uploadChunk(fileKey, chunkFile, uploadId, chunkSize, index + 1, offset, (percent) => {
          console.log(percent.toFixed(2) + '%');
        });
      });

      Promise.all(promises).then(partsInfo => {
        const parts = partsInfo.map(part => {
          return {
            partNumber: part.partNumber,
            etag: part.etag,
          };
        });

        const sortedParts = parts.sort((a, b) => a.partNumber - b.partNumber);

        // 完成上传
        qiniu.rpc.completeMultipartUpload(mac, bucket, fileKey, uploadId, sortedParts).then(result => {
          console.log(result);
          resolve(result);
        }).catch(err => {
          reject(err);
        });
      }).catch(err => {
        reject(err);
      });
    }).catch(err => {
      reject(err);
    });
  });
}

const localFile = '/path/to/local/file';
const fileKey = 'test.jpg';
uploadFile(localFile, fileKey)
.then(res => {
  console.log(res);
})
.catch(err => {
  console.error(err);
});

示例二:上传文件到阿里OSS

在这个示例中,我们将使用ali-oss库,将文件上传到阿里云OSS中。

const path = require('path');
const OSS = require('ali-oss');
const { accessKeyId, accessKeySecret, bucket } = require('./config');

const client = new OSS({
  region: 'oss-cn-beijing',
  accessKeyId,
  accessKeySecret,
  bucket,
});

function uploadChunk(fileKey, localfile, partNum, uploadId, fromByte, toByte, progressCallback) {
  return new Promise((resolve, reject) => {
    const options = {
      partNumber: partNum,
      uploadId,
      fromByte,
      toByte,
      progress: progressCallback,
    };
    client.uploadPart(fileKey, localfile, options).then(result => {
      const part = {
        PartNumber: options.partNumber,
        ETag: result.res.headers.etag,
      };
      resolve(part);
    }).catch(err => {
      reject(err);
    });
  });
}

function uploadFile(localFile, fileKey, fileSize) {
  return new Promise((resolve, reject) => {
    client.initMultipartUpload(fileKey, { timeout: 3600000 }).then(result => {
      const uploadId = result.uploadId;
      const chunkSize = 1024 * 1024;
      const chunkCount = Math.ceil(fileSize / chunkSize);
      const partList = Array.apply(null, {length: chunkCount}).map((_, index) => {
        const haveRead = (index * chunkSize);
        const toByte = Math.min((index + 1) * chunkSize, fileSize) - 1;
        const options = {
          partNumber: index + 1,
          fromByte: haveRead,
          toByte,
        };
        return options;
      });

      // 上传分片
      const promises = partList.map((part, index) => {
        const start = index * chunkSize;
        const end = (index + 1) * chunkSize - 1 >= fileSize ? fileSize : (index + 1) * chunkSize;
        const offset = start;
        const chunkFile = path.resolve(chunkDir, `${fileKey}.${uploadId}.${index}`);
        return uploadChunk(fileKey, chunkFile, part.partNumber, uploadId, start, end, percent => {
          console.log(percent);
        });
      });

      Promise.all(promises).then(parts => {
        console.log(parts);
        client.completeMultipartUpload(fileKey, uploadId, parts).then(result => {
          console.log(result);
        }).catch(err => {
          reject(err);
        });
      }).catch(err => {
        console.error(err);
      });
    }).catch(err => {
      reject(err);
    });
  });
}

const localFile = '/path/to/local/file';
const fileKey = 'test.jpg';
const fileSize = getFilesizeSync(localFile);
uploadFile(localFile, fileKey, fileSize).then(result => {
  console.log(result);
}).catch(err => {
  console.error(err);
});

以上便是“基于Node.js的大文件分片上传示例”的完整攻略,希望对您有所帮助。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:基于Node.js的大文件分片上传示例 - Python技术站

(0)
上一篇 2023年6月8日
下一篇 2023年6月8日

相关文章

  • nodejs管理工具nvm安装过程详解

    Nodejs管理工具nvm安装过程详解 什么是nvm nvm (node version manager) 是一个用于管理多个Nodejs版本的工具。它可以让你在同一台机器上轻松地切换不同版本的Nodejs,从而在不同的项目中使用不同的Nodejs版本。 安装nvm 步骤一:获取nvm安装脚本 你可以在github上的nvm仓库获取nvm的安装脚本。使用cu…

    node js 2023年6月8日
    00
  • node.js文件系统模块和两个重要模块

    我来为你讲解Node.js文件系统模块和两个重要模块的相关知识。 什么是Node.js文件系统模块? 在Node.js中,文件系统模块(fs模块)是一个用于处理计算机文件系统的模块。它允许我们读取和写入文件、创建新文件、修改现有文件等等。fs模块是Node.js的内置模块,无需安装即可使用。 以下是文件系统模块提供的一些方法: fs.readFile(fil…

    node js 2023年6月8日
    00
  • node.js文件上传重命名以及移动位置的示例代码

    下面我会给出一个使用Node.js实现文件上传、重命名以及移动位置的示例代码,并讲解具体步骤。 环境准备 在开始之前,我们需要确保计算机上已经安装了Node.js。同时需要安装以下两个Node.js模块: formidable:用于处理文件上传; fs:用于处理文件操作。 可以通过以下命令进行安装: npm install formidable fs 文件上…

    node js 2023年6月8日
    00
  • WebStorm ES6 语法支持设置&babel使用及自动编译(详解)

    WebStorm ES6 语法支持设置 & Babel 使用及自动编译 (详解) WebStorm 是目前市面上最为流行的前端开发 IDE 之一,同时也支持 ES6 语法的开发,本文将详细讲解 WebStorm 如何设置 ES6 语法支持和使用 Babel 自动编译。 设置 WebStorm ES6 语法支持 在 WebStorm 中开启 ES6 语…

    node js 2023年6月8日
    00
  • NodeJS学习笔记之网络编程

    NodeJS学习笔记之网络编程 学习NodeJS的网络编程,首先需要掌握以下几个核心概念:网络、协议、IP地址、端口、TCP协议和UDP协议。 网络概念 网络是指两台或多台计算机通过物理设备(例如交换机、路由器)或者空气波段(例如无线局域网)连接在一起,进行数据交换和资源共享的物理和逻辑集合体。 协议概念 网络中,协议是指计算机和计算机之间进行通讯时所采用的…

    node js 2023年6月7日
    00
  • Koa 中的错误处理解析

    Koa 是一个现代化的 Node.js 框架,具有轻量、高效、可定制等特点。在使用 Koa 进行开发的过程中,经常需要对错误进行处理。本文将为大家详细讲解如何在 Koa 中进行错误处理。 1. 错误处理的重要性 在任何项目中,错误都是难免的。对错误进行及时有效的处理,能够提高程序的鲁棒性和健壮性;而忽略错误的处理,则容易导致应用出现不可预料的问题,甚至引发系…

    node js 2023年6月8日
    00
  • Nest.js环境变量配置与序列化详解

    下面就来详细讲解“Nest.js环境变量配置与序列化详解”的完整攻略,包含以下几个部分: 环境变量的概念和在Nest.js中的应用 配置环境变量的方法 序列化和反序列化的概念和应用 序列化和反序列化的使用方法 1. 环境变量的概念和在Nest.js中的应用 环境变量是指在操作系统中设定的变量,用于表示一些程序运行时需要用到的值。在Nest.js中,我们可以通…

    node js 2023年6月8日
    00
  • js 如何实现对数据库的增删改查

    首先,需要明确的是,JavaScript本身是一门客户端语言,不具备直接对数据库进行操作的能力。但是,在Web开发中,我们常常使用JavaScript来与后端进行交互,从而实现对数据库的增删改查。 以下是一个基本的流程: 后端提供API接口,支持前端通过AJAX等方式发送请求(如GET、POST、PUT、DELETE等),并返回对应的数据(如JSON格式)。…

    node js 2023年6月8日
    00
合作推广
合作推广
分享本页
返回顶部