当我们在使用Node搭建服务端的时候,我们可能会碰到需要接收 压缩文件 的情况,例如:接收前端提交的压缩包、解压等,我们这里演示一下如何 接收 与 解压
前端
html
<!-- pages/index.html -->
<p id="desc">点击或拖拽文件到网页内即可上传</p>
css
/* pages/index.html */
* {
margin: 0;
padding: 0;
list-style: none;
border: none;
box-sizing: border-box;
}
html,
body {
width: 100vw;
height: 100vh;
}
#desc {
position: fixed;
top: 50%;
left: 50%;
letter-spacing: 1em;
font-size: 1.25rem;
color: #7c7c7c;
transform: translate(-50%, -50%);
z-index: -9999;
}
js
// pages/index.html
(() => {
let body = document.body
body.addEventListener('dragenter', e => e.preventDefault(), false)
body.addEventListener('dragleave', e => e.preventDefault(), false)
body.addEventListener('dragover', e => e.preventDefault(), false)
// 拖拽上传
body.addEventListener('drop', e => {
e.preventDefault()
let fileList = e.dataTransfer.files
beforeUpload(fileList)
}, false)
// 点击上传
body.addEventListener('click', () => {
let fileInput = document.createElement('input')
fileInput.type = 'file'
fileInput.click()
fileInput.onchange = function () {
beforeUpload(this.files)
}
}, false)
// 处理要上传的文件
function beforeUpload(fileList) {
// 检测是否是拖拽文件到页面的操作
if (fileList.length === 0) {
alert('未选择要上传的文件')
return
}
// 检测文件是不是zip压缩包
if (fileList[0].type.indexOf("application/zip") === -1) {
alert('只能上传zip格式的压缩包')
return
}
let formData = new FormData()
formData.append('file', fileList[0])
request(formData)
}
// 发送请求
function request(formData) {
let xhr = new XMLHttpRequest()
xhr.open('POST', '/api/upload')
xhr.send(formData)
xhr.onload = function () {
let { response } = this
response = JSON.parse(response)
if (response.code === 200 && response.state === true) {
alert(`上传成功`)
} else {
alert(`上传失败,${response.message}`)
}
}
}
})()
后台
后台采用express搭建,执行以下命令进行依赖安装:
yarn add express body-parser multer compressing
或
npm i express body-parser multer compressing -S
我们的目录结构如下:
node_modules
cache
pages
- index.html
service
- index.js
utils
- index.js
main.js
package.json
入口文件
// main.js
const express = require('express')
const bodyParser = require('body-parser')
const router = require('./service/index')
const path = require('path')
const app = express()
app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json())
app.use(express.static(path.resolve(__dirname, 'pages')))
app.use(router)
app.listen(8080, () => {
console.log(`服务器运行于 http://127.0.0.1:8080`)
})
自定义工具函数
// utils/index.js
const fs = require('fs')
const compressing = require('compressing');
// 写入文件
exports.writeFile = (filepath, data, encode) => {
return new Promise((resolve, reject) => {
fs.writeFile(filepath, data, encode, (err) => {
if (err) reject(err)
resolve()
})
})
}
// 读取文件
exports.readFile = (filepath, encode) => {
return new Promise((resolve, reject) => {
fs.readFile(filepath, encode, (err, data) => {
if (err) reject(err)
resolve(data)
})
})
}
// 解压文件
exports.extract = (filepath, outputPath) => {
//
return compressing.zip.uncompress(filepath, outputPath, {
// 设置中文解码,重要!!!
zipFileNameEncoding: 'utf8'
})
}
// 删除文件和文件夹
exports.delDir = (filepath) => {
if (fs.existsSync(filepath)) {
const files = fs.readdirSync(filepath)
files.forEach((file) => {
const nextFilePath = `${filepath}/${file}`
const states = fs.statSync(nextFilePath)
if (states.isDirectory()) {
this.delDir(nextFilePath)
} else {
fs.unlinkSync(nextFilePath)
}
})
fs.rmdirSync(filepath)
}
}
路由文件
// router/index.js
const router = require('express').Router()
const fs = require('fs')
const multer = require('multer')
const path = require('path')
const { writeFile, extract, delDir } = require('../utils/index')
// 压缩文件存放的位置
const filePath = path.resolve(__dirname, '../', 'cache')
router.post('/api/upload', multer().single('file'), async (req, res) => {
// multer 会自动将文件数据绑定到req.file中
let file = req.file
if (file.mimetype !== 'application/zip') {
res.send({ code: 400, state: false, message: '不是zip文件', data: 0 })
}
try {
// 删除旧目录
delDir(filePath)
// 重建压缩文件存放的目录
fs.mkdirSync(filePath)
// 得到压缩包的文件名
let filename = path.join(filePath, file.originalname)
// 保存压缩包文件,file.buffer存放文件的二进制数据
await writeFile(filename, file.buffer, 'buffer')
// 解压压缩包
await extract(filename, filePath)
// 解压完成后,删除压缩包
fs.unlinkSync(filename)
res.send({ code: 200, state: true, message: 'ok' })
} catch (error) {
console.log(error)
res.send({ code: 400, state: false, message: 'zip文件解压失败', data: 0 })
}
})
module.exports = router
其他
我们解压使用的是 compressing 处理的,并且 一定要记得设置中文解码,否则可能会出现中文乱码
当然,例如 node-stream-zip 和 extract-zip 也无法解析中文,会出现乱码