将 express post 体限制增加到代理 api

increase express post body limit to proxied api

我有一个单独的前端和后端,所有对 http://frontend.com/api 的请求都被代理到后端。但是,我们允许图片上传最大为 10mb,这受到所有请求主体上 express 1mb 内部限制的限制。

我有以下配置:

const express = require('express');
const consola = require('consola');
const { Nuxt, Builder } = require('nuxt');
const helmet = require('helmet');

// Express
const app = express();
const host = process.env.HOST || '127.0.0.1';
const port = process.env.PORT || 8080;

app.set('port', port);

// Import and Set Nuxt.js options
const config = require('../nuxt.config.js');

config.dev = !(process.env.NODE_ENV === 'production');

async function start() {
  // Init Nuxt.js
  const nuxt = new Nuxt(config);

  if (config.dev) {
    const builder = new Builder(nuxt);
    await builder.build();
  }

  // NOTE: Only in production mode
  if (!config.dev) {
    // Helmet default security + Referrer + Features
    app.use(helmet());
  }

  // Proxy /api to proper backend
  app.use('/api', proxy(process.env.API_ENDPOINT || 'http://localhost:3000'));

  // Give nuxt middleware to express
  app.use(nuxt.render);

  // Listen the server
  app.listen(port, host);
  consola.ready({
    message: `Server listening on http://${host}:${port}`,
    badge: true,
  });
}
start();

我尝试添加正文解析器,直到我发现这只适用于非 multipart/form 类型的请求。考虑到这不是一个快速后端,而是仅用于服务 SSR(使用 nuxt),我不知道如何让它与 multer 或 busboy 之类的东西一起工作。

无需将 nginx 设置为反向代理就可以做到这一点吗?

我的工作方式是在一个配置文件中定义我的 api 基础 url,我在 api/init.js 文件中引用该文件。此文件已添加到 nuxt.config.js 中的插件。这是那个文件:

import axios from 'axios'
import {baseURL} from '~/config'
import cookies from 'js-cookie'
import {setAuthToken, resetAuthToken} from '~/utils/auth'
import { setUser, setCart } from '../utils/auth'

axios.defaults.baseURL = baseURL

const token = cookies.get('x-access-token')
const currentUser = cookies.get('userDetails')
const currentCart = cookies.get('userCart')

if (token) {
    setAuthToken(token)
    setUser(currentUser)
    setCart(currentCart)
} else {
    resetAuthToken()
}

后端在我用 node index.js 启动的自己的服务器上运行,它是我的 init.js 寻找的基础 url。后端 index.js 看起来像这样:

const mysql = require('mysql')
const express = require('express')
const bodyParser = require('body-parser')
const config = require('./config')
const jwt = require('jsonwebtoken')
const bcrypt = require('bcrypt')
const multer = require('multer')
const auth = require('./auth')
const files = require('./files')
const create = require('./create')
const get = require('./get')
const delet = require('./delet')
const blogFiles = require('./blogFiles')

const db = mysql.createConnection(config.db)
const app = express()

app.use(bodyParser.json())
app.use(bodyParser.urlencoded({
  extended: true
}))

app.use((req, res, next) => {
    res.header('Access-Control-Allow-Origin', '*')
    res.header('Access-Control-Allow-Methods', 'GET, PUT, POST, DELETE, OPTIONS')
    res.header('Access-Control-Allow-Headers', 'Content-Type, Content-Length, x-access-token, userDetails, userCart')
    if (req.method === 'OPTIONS') {
      res.sendStatus(200)
    }
    else {
      next()
    }
})

app.use((err, req, res, next) => {
  if (err.code === 'LIMIT_FILE_TYPES') {
      res.status(422).json({ error: 'Only images are allowed'})
      return
  }
  if (err.code === 'LIMIT_FILE_SIZE') {
      res.status(422).json({ error: `Too Large. Max filesize is ${MAX_SIZE/1000}kb` })
      return
  }
})

app.use('/auth', auth({db, express, bcrypt, jwt, jwtToken: config.jwtToken}))
app.use('/files', files({db, express, multer}))
app.use('/blogFiles', blogFiles({db, express, multer}))
app.use('/create', create({db, express}))
app.use('/get', get({db, express}))
app.use('/delet', delet({db, express}))

app.get('/test', (req, res) => {
  db.query('select 1+1', (error, results) => {
    if (error) {
      return res.status(500).json({type: 'error', error})
    }
    res.json({type: 'success', message: 'Test OK', results})
  })
})

app.listen(config.port)
console.log('App is running on port ' + config.port)

files.js 处理文件上传,如您所见,index.js 需要这样做。我在那里使用 multer 来处理上传限制等。这是file.js

module.exports = ({db, express, multer }) => {
    const routes = express.Router()

    const fileFilter = function(req, file, cb) {
        const allowedTypes = ['image/jpeg', 'image/png', 'image/gif']
        if (!allowedTypes.includes(file.mimetype)) {
            const error = new Error('Wrong file type')
            error.code = 'LIMIT_FILE_TYPES'
            return cb(error, false)
        }

        cb(null, true)
    }

    const MAX_SIZE = 250000

    var storage = multer.diskStorage({
        destination: function (req, file, cb) {
          cb(null, '../frontend/assets/images')
        },
        filename: function (req, file, cb) {
          cb(null, file.originalname)
        }
      })

    const upload = multer ({
        storage: storage,
        fileFilter,
        limits: {
            fileSize: MAX_SIZE
        },

    })

    routes.post('/upload', upload.single('file'), (req, res) => {
      res.json({ file: req.file })
    })

    return routes
  }

如您所见,我在此处为我的文件上传设置了 MAX_SIZE,因此您可以设置任何限制,并且当 multer 处理它时,它将超越 express 设置的任何限制。

Express 本身不对正文大小施加任何限制,因为它根本不处理请求正文。

但是,某些中间件 施加了限制,例如 body-parserexpress-http-proxy,这就是您正在使用的。

要将限制增加到 10MB:

app.use('/api', proxy(process.env.API_ENDPOINT || 'http://localhost:3000', {
  limit: '10mb'
));