http 流文件接收与上传

117 阅读1分钟

1.接收流

<!-- 表单是一个流数据 -->
<form action="/api/save" method="post">
<input type="text" name="abc" value="123">
<input type="submit" value="save"> 
</form>

后台代码

//方法1 传统的http实现
//http 代码 注意这里缺点是 buffer会一直占用内存
if (method === "POST" && url === "/api/save") { 
    let reqData = []; 
    let size = 0; 
    //通过流 一点一点的把水接起来
    req.on('data', data => { 
        console.log('>>>req on', data); 
        reqData.push(data); 
        size += data.length; 
    });  
    //接完合并数据
    req.on('end', function () { 
        console.log('end') 
        const data = Buffer.concat(reqData, size); 
        console.log('data:', size, data.toString()) 
        res.end(`formdata:${data.toString()}`) 
    }); 
}

//方法2 koa实现
app.use(async (ctx, next) => {
    console.log('body-parser.....')
    const req = ctx.request.req
    let reqData = [];
    let size = 0;
    await new Promise((resolve,reject) => {
        req.on('data', data => {
            console.log('>>>req on',data);
            reqData.push(data);
            size += data.length;
        });
        req.on('end', function () {
            console.log('end')
            const data = Buffer.concat(reqData, size);
            console.log('data:', size, data.toString())
            ctx.request.body = data.toString()
            resolve()
        });
    })
    await next();
});


//方法3 koa + koa-bodyparser实现
const bodyParser = require('koa-bodyparser')
//添加中间件 就可以正常接收流,自动转化
app.use(bodyParser())
router.post('/add', async (ctx, next) => {
    console.log('body', ctx.request.body)//这里body已经被自动转化
    ctx.body = ctx.request.body 
    next()
})


上传文件

index.html

<html>
<head>
<title>file test</title>
<script>
window.onload=function(){
    var files = document.getElementsByTagName('input'),
    len = files.length,
    file;
    for (var i = 0; i < len; i++) {
        file = files[i];
        if (file.type !== 'file') continue; // 不是文件类型的控件跳过
        file.onchange = function() {
            var _files = this.files;
            if (!_files.length) return;
            if (_files.length === 1) { // 选择单个文件
                var xhr = new XMLHttpRequest();
                xhr.open('POST', 'http://127.0.0.1:3000/upload');
                var filePath = files[0].value;
                xhr.setRequestHeader('file-name', filePath.substring(filePath.lastIndexOf('\\') + 1));
                xhr.send(_files[0]);
            } else { }
        };
    }
};
</script>
</head>
<body>
    <input id='file1' type="file" />
</body>
</html>

index.js

const http = require('http')
const fs = require('fs')
const path = require('path')
const chunk = []
let size = 0
const server = http.createServer((request, response) => {
    const { pathname } = require('url').parse(request.url)

    if (pathname === '/upload') {
        console.log('upload....')
        //方法1 //利用fis文件写入,可以优化buffer 占用缓存问题。
        const fileName = request.headers['file-name'] ? request.headers['file-name'] : 'abc.png'
        const outputFile = path.resolve(__dirname, fileName) 
        const fis = fs.createWriteStream(outputFile) 
        request.pipe(fis)//由于是直接pipe,pipe是异步,无法确定是否输出成功
        response.end()
        
        //方法2 使用buffer确定在end 全部完成后执行后续结果
        // Buffer connect
        // request.on('data',data => {
        //     chunk.push(data)
        //     size += data.length
        //     console.log('data:',data ,size)
        // })
        // request.on('end',() => {
        //     console.log('end...')
        //     const buffer = Buffer.concat(chunk,size)
        //     size = 0
        //     fs.writeFileSync(outputFile,buffer)
        //     response.end()
        // })

        // 方法3 流事件写入,每次直接写入流,是写在硬盘伤的,不占用内存buffer
        // request.on('data', data => {
        //     console.log('data:',data)
        //     fis.write(data)
        // })
        // request.on('end', () => {
        //     fis.end()
        //     response.end()
        // })
    }
})
server.listen(3000)