egg.js 文件上传转发

3,109 阅读3分钟

缘由

开发的项目是egg.js + redis + mysql + vue2.x 全家桶 全栈开发的项目,由于需要做文件上传,上传成功后还要给文件生成文件目录结构,然后还需要做压缩进行处理,并且文件太大,这样一来上传的速度肯定会特别慢,处理起来也比较复杂。于是就偷个懒,丢给我们后台去处理。因为 Python处理肯定性能上要好很多(其实是自己偷懒 ^_^)但是也要对接口做二次封装. 最初的想法是前端直接调后台,但是经理要求要封装一层,没办法,只能在node中调后台的接口,也就是 前端上传文件到node层 node接收文件再模拟Formdata 上传将文件发到 后台 python 中。于是就开始码代码,问题就因此产生 node怎么模拟表单上传?

网上搜索半天,都是拼接参数,嗯,最怕的就是搞这么复杂的了,后来通过搜索npm插件,尼玛 找到了一款 form-data 插件,使用时候 后台死活也接收不到文件 后来想到了一款牛逼的插件 [superagent] [www.npmjs.com/package/sup…] www.jianshu.com/p/1432e0f29… 嗯,真香 什么请求代理 转发 统统搞定 用来做爬虫也足够强大,开始码代码,先来个node 前端就不写了,vue+axios + elementui 上传

eggjs 使用 eggjs 进行配置

config.multipart = { mode: "Stream", fileSize: "1024mb" };

关于 stream的了解,可以百度,相关文章很多。

'use strict';
 
const Service = require('egg').Service;
const path = require("path");
const request = require('superagent'); 
const sendToWormhole = require('stream-wormhole');
const fs = require('fs');
const toArray = require('stream-to-array');
class formService extends Service {
    async index() {
        const ctx = this.ctx;
        const url = 'http://xxxxx/eggpost/';
        const stream = await ctx.getFileStream();
        const target = path.join(this.config.baseDir, 'app/public', stream.filename);
        let result;
        try {
            const parts = await toArray(stream);
            let buf = Buffer.concat(parts);
            // 写入文件保存至本地
            fs.writeFileSync(target, buf);
            result = await request
                .post(url)
                .attach('file', target, stream.filename)
        } catch (err) {
            // 必须将上传的文件流消费掉,要不然浏览器响应会卡死
            await sendToWormhole(stream);
            throw err;
        }
        //在上传完毕后删除文件
        fs.unlink(target, function (err) {
            if (!err) {
                console.log('文件已删除:', target);
            }
        });
        return {
            result:result.text
        }
    }
}
 
module.exports = formService;

Python 代码

直接采用的 django 来实现,上代码

def eggpost(request):
    if request.method == 'GET':
        pass
    else:
        try:
            files = request.FILES.getlist('file')
            for f in files:
                destination = open(os.path.join(BASE_DIR, 'static', 'images', f.name), 'wb+')
                for chunk in f.chunks():
                    destination.write(chunk)
                destination.close()
 
            msg = {
                'status': 200,
                'msg': '上传成功',
            }
        except Exception as e:
            print(e)
            msg = {
                'status': 500,
                'msg': '上传失败',
            }
 
        return HttpResponse(json.dumps(msg,ensure_ascii=False))

这样就上传成功了,很简单有木有? 其实也想过通过proxy代理中间件转发,但是又有问题,实现原理也是转发接口,element 里面会有延迟的问题,经过实践,最终采用这种方法。

代码看起来还是挺简单的,但是对于有些人还是有些帮住的,中间也踩了不少坑,最后也都是还是解决了,有更好的实现方式 请指教~~

后来看到了有人也发了相关的转发思路,我只不过把自己的代码也贴出来,提供一种思路,不喜欢的请轻点喷哦

相关链接