关于node 中间层代理接口 使用stream 的方式转发接口,前端formdata传递的文件会丢失
发布于 5 年前 作者 AREA-CQK 7113 次浏览 来自 问答

**前提: **

  1. Node中间层服务是采用egg.js 开发,
  2. 会代理接口 ,对请求有些处理,在转发后端
  3. 想采用stream的方式对接口进行代理 场景 前端formdata上传文件,原采用方式是用egg封装的ctx.getFileStream获取文件流 写入buffer,再使用 superagent 的atach 使用buffer 上传给后端, 现准备采用类似 req.pipe(res) 的模式 进行请求 采用的request的流
ctx.body = request({ uri,   method,  ...requestOption.headers  })
.on('response', response => {
Object.keys(response.headers).forEach((key) => {
// if ('content-length' === key) return;
if ('transfer-encoding' === key) return;
	ctx.set(key, response.headers[key]);
});
})
.on('error', (error) => {
	console.log(error)
})
 .pipe(PassThrough())

但是发现转发后无法携带file文件流 后端无法获取到file 有没有一些好的方法解决代理 文件传输 或者 以上的方式可携带上文件流?

8 回复

我使用的axios,request类似,参考如下

app.use(async ctx => {
  const options = {
    url: 'http://localhost:3000', // 代理的地址
    method: ctx.request.method,
    headers: ctx.request.headers,
    responseType: 'stream',
  };

  if (ctx.request.body && Object.keys(ctx.request.body).length) {
    options.data = ctx.request.body;
  } else {
    // 上传文件,直接把ctx.req原生的req流传给data
    options.data = ctx.req;
  }

  const result = await axios(options).catch(err => {
    if (!err || !err.response) {
      throw err || new Error('axios unknown error');
    }
    return err.response;
  });

  ctx.res.statusCode = result.status;
  ctx.status = result.status;
  await new Promise((resolve, reject) => {

    for (const key in result.headers) {
      ctx.set(key, result.headers[key]);
    }
    // axios返回的response数据注入到ctx.res
    result.data.pipe(ctx.res);
    result.data.on('end', () => {
      return resolve();
    });
    result.data.on('error', err => {
      return reject(err);
    });
  });
});

大佬, 现在有解决方案了吗?

楼主先搞明白 promise 和 callback 吧, koa 不支持 callback 的方式

代理不是你随便用一个 request 就可以搞定的,有很多坑需要填的,可以参考下 https://github.com/eggjs/egg-http-proxy 的源码

包一下就好了

await new Promise(function(resolve, reject){
    // 逻辑自己包
	request({ uri,   method,  ...requestOption.headers  })
.on('response', response => {
Object.keys(response.headers).forEach((key) => {
// if ('content-length' === key) return;
if ('transfer-encoding' === key) return;
	ctx.set(key, response.headers[key]);
});
})
.on('error', (error) => {
	console.log(error)
})
 .pipe(PassThrough())
})

@i5ting 代理没那么简单的,看我那个库里面那么多代码就知道了(即便如此,我那个库其实还有一些 edge case 没处理的)

就楼主的需求而言,可以直接用我那个库提供的 API

@atian25 嗯,他是request透传,还好,加中间人就麻烦了。你那个库确实更合适

回到顶部