Nodejs代理实现文件上传/下载时要注意的问题


  当前许多前端应用都存在node层,并通过node层做上传/下载代理(当然通过nginx代理应该是首选),本文主要介绍几个代理的插件和其中存在的坑,希望对大家的上传/下载研发方案有帮助。

nodejs环境:10.18.0 | eggjs版本:2.29.4 | koa-proxies版本:0.12.1 | koa2-nginx:2.0.2

代理插件

  本文不是介绍插件怎么用的,如需详细了解相关知识,可以直接看插件的文档或者代码,本文主要介绍功能实现,需要问题和解决办法。本文主要需求是通过post来实现参数传递,流文件实现下载。

(1)koa2-proxies

地址:https://github.com/vagusX/koa-proxies
存在问题:这个版本对于Content-Type: multipart/form-data能够很好的处理,但是对于Content-Type: application/json会导致请求头和body无法上传(这个已经有人提bug了,见图1),导致nginx端读取不到数据而出现连接超时408错误。

如下代码片段是一个典型的代理实现。

router.post(
  '/downloadproxy',
  proxy('/download', params => {
    return {
      target,
      changeOrigin: true,
      logs: true,
      rewrite: path => {
        return path.replace('/downloadproxy', '/download')
      }
    }
  })
)
图 1 koa2-proxies的github的issues列表

(2)koa2-nginx

npm地址:https://www.npmjs.com/package/koa2-nginx
这个插件是解决了koa2-proxies对于body的处理问题,需要加入参数autoProcessReqBody。

如下是典型的实现应用。

await proxy({
  context: '/downloadproxy',
  pathRewrite: {
    '^/downloadproxy': ''
  },
  target,
  changeOrigin: true,
  autoProcessReqBody: true
})(this.ctx)

(3)非插件解决body缺失问题

  当请求的 Content-Type 为 application/json,application/json-patch+json,application/vnd.api+json 和 application/csp-report 时,eggjs会按照json格式对请求body进行解析,并限制body最大长度为100kb。
  回到上面的问题,为啥会丢失body,主要是eggjs的bodyparser默认为开启状态,这时候,它会消费从页面发送来的body,导致body缺失,会让nginx认为这个请求等待header信息,最后超时。这时候可以这样设置,关闭bodyparser:

exports.bodyParser = {
  ignore: ['/api/download/*'], //需要忽略body消费的api匹配规则
};
图 2 bodyParser配置参数

下载请求

  通过axios请求下载文件时需要注意配置responseType,一般通过Blob的方式来缓存stream流数据,并保存为其他格式,比如保存为zip文件,这是responseType必须设置为blob,否则zip文件将打开出错。

axios的典型实现如下:

axios({
  method: 'post',
  url: '/download',
  data: {
  	parameters: 'some parameters'
  },
  responseType: 'blob'
})

其中responseType的主要类型如下:

// 选项包括: 'arraybuffer', 'document', 'json', 'text', 'stream'
// 浏览器专属:'blob'
responseType: 'json', // 默认值

保存文件的实现方式

const contentType = res['headers']['content-type'] || res['headers']['Content-Type']
const fileName = res['headers']['content-disposition'].split('filename=')[1]

if (!fileName) {
  toBuffer(res.data, function(err, buffer) {
    const str = buffer.toString() || ''
    console.log('下载失败')
  })
} else {
  const url = window.URL.createObjectURL(new Blob([res.data], { type: contentType }))
  const downloadElement = document.createElement('a')
  downloadElement.href = url
  downloadElement.setAttribute('download', fileName)
  document.body.appendChild(downloadElement)
  downloadElement.click()
  document.body.removeChild(downloadElement)
  window.URL.revokeObjectURL(url)
}

ps: 通过Node层进行代理上传下载的坑比较多,推荐使用Nginx能省去不少麻烦。

参考文献

  1. Eggjs bodyParser
  2. Nginx包含图片请求频繁报408错误码
  3. koa2-nginx说明文档
  4. axios关于request的配置说明
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

呵呵你真行

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值