大文件分片上传-后端端部分(server.js)

使用fs模块的读流写流方式将文件合并

我遇到的问题:

1. 切片是正常上传的,但是同一个图片多次上传,有时候合并的文件是正确的,能够预览,有的时候无法解析
2. 猜测: 每一个切片的读流写流是异步操作,在merge(index) 和 merge(index+1)可能存在冲突,而且pipe后写流是默认关闭的,所以加了
     rs.pipe(ws, {end: false}) // 需要合并多次,不关闭ws,
     rs.on('end', () => { // 读完之后在合并下一个片段
       merge(index + 1)
     })

如何跑起来

1. 将index.html 和 server.js放在同一个文件夹,在cmd使用 `http-server` 挂在前端index.html
2. 使用cnpm下载koa, koa-body然后使用node(version=10+)运行server.js
const koa = require('koa')
const koaBody = require('koa-body')
const fs = require('fs')

const app = new koa()

// 使用koaBody托管上传文件,koaBody会自动把文件上传到upload文件夹里,并且以一个随机字符串命名
app.use(koaBody({
    multipart: true,
    formLimit: 15,
    formidable: {
      uploadDir: __dirname + '/upload'
    }
  })
)

app.use(async (ctx, next) => {
    // 解决跨域
    ctx.set('Access-Control-Allow-Origin', '*');
    ctx.set('Access-Control-Allow-Headers', 'Content-Type, Content-Length, Authorization, Accept, X-Requested-With , yourHeaderFeild');
    ctx.set('Access-Control-Allow-Methods', 'PUT, POST, GET, DELETE, OPTIONS');
    await next();
});

app.use(async (ctx, next) => {
    if(ctx.path === '/upload') {
        // 上传到后端的文件名重新命名下, 合并时才找得到
        let fd = ctx.request.body
        let filePath = ctx.request.files.file.path
        let newFileName = `${fd.fileName}-${fd.index}-${fd.uuid}`
        let newFilePath = filePath.substr(0, filePath.lastIndexOf('\\') + 1) + newFileName
        fs.renameSync(filePath, newFilePath)
        ctx.body='upload success'
    }
    else if(ctx.path === '/merge') {
        let {uuid, count, fileName} = ctx.request.body
        let ws, rs
        function merge(index) {
            if(index >= count) {
                ws && ws.close()
                // read流默认autoclose
                return
            }
            rs = fs.createReadStream(__dirname +  '/upload/' + `${fileName}-${index}-${uuid}`)
            ws = fs.createWriteStream(__dirname +  '/upload/' + `${uuid}-${fileName}`, { flags: 'a' }) // 以追加的方式插入数据

            rs.pipe(ws, {end: false}) // 需要合并多次,不关闭ws,
            rs.on('end', () => { // 读完之后在合并下一个片段
                merge(index + 1)
            })
        }
        merge(0)
        ctx.body='merge success'
    }
    await next()
})

app.listen(8081, () => {
    console.log('on')
})
Html
JSRUN前端笔记, 是针对前端工程师开放的一个笔记分享平台,是前端工程师记录重点、分享经验的一个笔记本。JSRUN前端采用的 MarkDown 语法 (极客专用语法), 这里属于IT工程师。