egg-ant-design-pro 的上传图片问题,proxy代理后七牛的上传把线程弄垮了?
发布于 5 年前 作者 thomas0836 3306 次浏览 来自 问答

基于 egg-ant-design-pro 实现上传图片裁剪的功能。 问题是这样的,egg-ant-design-pro 的 proxy 比较简单的做一个get 的代理,其他一些复杂一点的需求基本实现不了。所以进行了一些小修改。

但是在上传文件的时候遇到了问题。文件流传到上传服务器的时候就报错了。而且目测是整个进程也死了,需要重新npm run dev才可以。

目前实现思路如下:

前端 通过dva的 request 把上传的文件传到 proxy ,通过了 const stream = await ctx.getFileStream() 获取到流,然后再通过formstream内的 stream('file', stream, filename, mimeType, size) 方法把流挂上去。然后proxyObj.stream = form传回给 const res = await this.ctx.curl(url, proxyObj);。最后到上传的服务器项目,再通过 const stream = await ctx.getFileStream()获取流。

具体代码如下。

egg-ant-design-pro 的 proxy 是这样的。

'use strict';

const Controller = require('egg').Controller;

class HomeController extends Controller {
  async index() {
    await this.ctx.render('index.html');
  }

  async proxy() {
    const ctx = this.ctx;
    // use roadhog mock api first
    const url = 'http://127.0.0.1:8000' + ctx.path + '?' + ctx.querystring;

    const res = await this.ctx.curl(url, {
      method: this.ctx.method,
    });
    ctx.body = res.data;
    ctx.status = res.status;
  }
}

module.exports = HomeController;

目前改成

'use strict';

const Controller = require('egg').Controller;
const FormStream = require('formstream');
class HomeController extends Controller {
  async index() {
    await this.ctx.render('index.html');
  }

  async proxy() {

    const { ctx, config, logger } = this;
    const { body, header } = ctx.request;
    // use roadhog mock api first
    const url = `${config.apiPath}${ctx.path}?${ctx.querystring}`;
    logger.info(`${ctx.method} ${url}`);

    const proxyObj = {
      method: ctx.method,
    };
    if (body) {
      proxyObj.data = { ...body };
    }
    if (header) {
      proxyObj.headers = { ...header };
      if (header['content-type'] && header['content-type'].indexOf('multipart') >= 0) {
        const stream = await ctx.getFileStream();
        const form = new FormStream();
        const { filename, mimeType, size } = stream;
        form.stream('file', stream, filename, mimeType, size);
        
        proxyObj.stream = form;
        proxyObj.headers = {
          ...header,
          ...form.headers(header),
        };
      }
    }

    const res = await this.ctx.curl(url, proxyObj);
    if (res.status !== 204) {
      ctx.body = res.data;
    }
    ctx.status = res.status;
    logger.info(`${ctx.method} ${url} ${res.status}`);
  }
}

module.exports = HomeController;

文件上传服务器


const Controller = require('egg').Controller;

class UploadController extends Controller {
  async img() {
    const { ctx, service } = this;
    console.log('img stream before');
    const stream = await ctx.getFileStream();
    const { qn } = service;
	const { filename } = stream;
    const res = await qn.upload(stream, filename);
    ctx.helper.success({ ctx, res });
  }
}

const res = await qn.upload(stream, filename); 这里就不行了。

[2018-12-12 19:15:17.416] [cfork:master:11561] worker:11563 disconnect (exitedAfterDisconnect: true, state: disconnected, isDead: false, worker.disableRefork: false)
[2018-12-12 19:15:17.416] [cfork:master:11561] don't fork new work (refork: false)
2018-12-12 19:15:17,416 INFO 11561 [master] app_worker#1:11563 disconnect, suicide: true, state: disconnected, current workers: ["1"]
[Wed Dec 12 2018 19:15:47 GMT+0800 (CST)] [graceful:worker:11563] kill timeout, exit now.
2018-12-12 19:15:47,405 ERROR 11563 [app_worker] exit with code:1
[2018-12-12 19:15:47.411] [cfork:master:11561] worker:11563 exit (code: 1, exitedAfterDisconnect: true, state: dead, isDead: true, isExpected: true, worker.disableRefork: false)
2018-12-12 19:15:47,412 ERROR 11561 nodejs.AppWorkerDiedError: [master] app_worker#1:11563 died (code: 1, signal: null, suicide: true, state: dead), current workers: []
    at Master.onAppExit (/Users/thomas/Documents/projects/u_login_api/node_modules/egg-cluster/lib/master.js:398:21)
    at Master.emit (events.js:180:13)
    at Messenger.sendToMaster (/Users/thomas/Documents/projects/u_login_api/node_modules/egg-cluster/lib/utils/messenger.js:133:17)
    at Messenger.send (/Users/thomas/Documents/projects/u_login_api/node_modules/egg-cluster/lib/utils/messenger.js:98:12)
    at EventEmitter.cluster.on (/Users/thomas/Documents/projects/u_login_api/node_modules/egg-cluster/lib/master.js:267:22)
    at EventEmitter.emit (events.js:185:15)
    at ChildProcess.worker.process.once (internal/cluster/master.js:194:13)
    at Object.onceWrapper (events.js:272:13)
    at ChildProcess.emit (events.js:180:13)
    at Process.ChildProcess._handle.onexit (internal/child_process.js:209:12)
name: "AppWorkerDiedError"
pid: 11561

const res = await qn.upload(stream, filename); 这里应该不是问题所在,因为在umi dev 的时候,直接到文件上传服务器是没有问题,可以正常上传到七牛云。

请问问题是在哪里,这里 proxy 对文件流的处理是否正确? 以上方法也是参考 egg官方文档 以-multipart-方式上传文件 来做的。

2 回复

umi dev 代理时直接到 文件上传服务器 时的 const stream = await ctx.getFileStream()

{
	"_readableState": {
		"objectMode": false,
		"highWaterMark": 16384,
		"buffer": {
			"head": {
				"data": {
					"type": "Buffer",
					"data": [, 217]
				},
				"next": null
			},
			"tail": {
				"data": {
					"type": "Buffer",
					"data": [255, 217]
				},
				"next": null
			},
			"length": 1
		},
		"length": 7178,
		"pipes": null,
		"pipesCount": 0,
		"flowing": null,
		"ended": true,
		"endEmitted": false,
		"reading": false,
		"sync": false,
		"needReadable": false,
		"emittedReadable": true,
		"readableListening": false,
		"resumeScheduled": false,
		"destroyed": false,
		"defaultEncoding": "utf8",
		"awaitDrain": 0,
		"readingMore": false,
		"decoder": null,
		"encoding": null
	},
	"readable": true,
	"_events": {},
	"_eventsCount": 2,
	"truncated": false,
	"fieldname": "file",
	"filename": "640.jpeg",
	"encoding": "7bit",
	"transferEncoding": "7bit",
	"mime": "image/jpeg",
	"mimeType": "image/jpeg",
	"fields": {}
}

egg 的 proxy 代理后 文件上传服务器 时的 const stream = await ctx.getFileStream()

{
	"_readableState": {
		"objectMode": false,
		"highWaterMark": 16384,
		"buffer": {
			"head": {
				"data": {
					"type": "Buffer",
					"data": [255, 217]
				},
				"next": null
			},
			"tail": {
				"data": {
					"type": "Buffer",
					"data": [255,217]
				},
				"next": null
			},
			"length": 1
		},
		"length": 8356,
		"pipes": null,
		"pipesCount": 0,
		"flowing": null,
		"ended": false,
		"endEmitted": false,
		"reading": true,
		"sync": false,
		"needReadable": true,
		"emittedReadable": false,
		"readableListening": false,
		"resumeScheduled": false,
		"destroyed": false,
		"defaultEncoding": "utf8",
		"awaitDrain": 0,
		"readingMore": false,
		"decoder": null,
		"encoding": null
	},
	"readable": true,
	"_events": {},
	"_eventsCount": 2,
	"truncated": false,
	"fieldname": "file",
	"filename": "640.jpeg",
	"encoding": "7bit",
	"transferEncoding": "7bit",
	"mime": "image/jpeg",
	"mimeType": "image/jpeg",
	"fields": {}
}
回到顶部