前言
因项目需要,后台需要支持接收前端的压缩文件并解析上传至云平台,一顿踩坑之后基本跑通了整条流程,下面写下来分享给那些像我一样的node小白~
实现过程
安装依赖
本次实现中依赖了node解压模块unzip
yarn add unzip
接收zip文件
之前在网上找了好多资料,基本上都是在服务器本地对各种文件进行操作,难道就没有从前端向后台传、解析压缩文件的先例嘛???
所以,直接从前端把zip文件抛过来,get!
项目UI是基于antd实现的,所以直接用Upload组件进行的上传,这里有个坑要踩,在默认设置下组件上传会报错:No 'Access-Control-Allow-Origin' header is present on the requested resource. 需要给组件设置属性
headers= {{ 'X-Requested-With':null }}
get是get到了,但通过fs.createReadStream()
来直接读取拿到的buffer是总是回报这样那样的错误,经过一番苦苦搜寻,找到了这样一种解释:This means the library would like to do its own reading of the file rather than being given a stream of bytes for analysis.,大概意思就是node的方法希望接收的资源是资源的路径而不是资源本身,既然这样,那就把从前端获取的数据先存起来好了:
fs.writeFile(`${__dirname}/temp/temp.zip`, z, function(e) {
···//这里的z就是从前端拿来的资源
}
这下就可以拿到想要的zip了吧,然后就可以为所欲为了。
fs.writeFile(`${__dirname}/temp/temp.zip`, z, function(e) {
fs.createReadStream(`${__dirname}/temp/temp.zip`) //拿到zip
.pipe(unzip.Parse()) //将流流入unzip.Parse
.on('entry', function(entry: any) {
let fileName = entry.path.replace(/[\w]+\//g, '').trim() // 将路径上的目录都剔除掉,只留下文件名
if ( fileName !== ".DS_Store" && fileName !== "desktop.ini" && entry.type === "File") {
// 这里的判断是因为在解析完压缩文件后发现每个目录下都有个叫.DS_Store的奇怪东西
// 查了才知道这是Mac系统的配置文件,这个当让不是我想上传的
// desktop.ini是windows系统的配置文件
entry.on('data', function(chunck: any) {
let bs = new Stream.PassThrough() //很奇葩,云平台的接口对数据有要求,不得已又又做了一次流的转换
bs.end(chunck)
arr.push(
new Promise(function(resolve, reject) {
formUploader.putStream(token.uploadToken, `${prePath}${fileName}`, bs, putExtra, function(err, res, info) { //这是向云平台上传文件的方法
if (err) {
reject(err)
}
if (info.statusCode === 200) {
resolve(res)
} else {
reject(res)
reject(info.statusCode)
}
})
})
)
})
}
})
.once('close', function() {
cb(arr) // 解压完成执行回调
})
}
unzip.Parse()方法是对压缩包进行递归解压,所以才能这么轻松的拿到解压后的所有文件,给它一个大大的赞~