You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用express.raw()处理文件上传时数据被截断的问题排查

问题

我正在运行Express.js 4.18.2,有一个用于存储二进制文件的路由。使用express.raw中间件时,生成的Buffer被截断——比如上传5k的测试文件,PUT路由中得到的Buffer的byteLength仅为1791字节。相关代码如下:

主应用代码

import createError from 'http-errors';
import express from 'express';
import path from 'path';
import cookieParser from 'cookie-parser';
import logger from 'morgan';
import status from 'http-status';
import storageObjectsRouter from './routes/stored-objects';
import { Request, Response, NextFunction } from 'express';
import fs from 'fs';
import { HttpError } from 'http-errors';
import mung from 'express-mung';
import cors from 'cors';

const port = 3000;
const app = express();
const dataDir = path.join(__dirname, 'data');
if (!fs.existsSync(dataDir)) {
  fs.mkdirSync(dataDir);
}
app.set('dataDir', dataDir);
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');
app.use(cors());
app.use(
  express.raw({
    type: (req) => {
      const contentType = req.headers['content-type'];
      console.debug(`Got content type ${contentType}`);
      if (
        contentType !== 'application/json' &&
        !contentType?.startsWith('text/')
      ) {
        return true;
      }
      return false;
    },
    limit: '1GB',
  })
);
app.use(
  mung.json((body, _req, res) => {
    console.debug('Munging json()');
    if (res.statusCode < 300) {
      body = { result: body };
    }
    return body;
  })
);
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));

app.use('/v1/stored-objects', storageObjectsRouter);

// catch 404 and forward to error handler
app.use(function (_req, _res, next) {
  next(createError(404));
});

// error handler
app.use(function (
  err: HttpError,
  req: Request,
  res: Response,
  _next: NextFunction
) {
  // set locals, only providing error in development
  res.locals.message = err.message;
  res.locals.error = err;

  const statusCode = err.status || 500;
  // render the error page
  res.status(statusCode).json({
    error: {
      statusCode,
      cause: status[statusCode],
      message: err.message || status[`${statusCode}_MESSAGE`],
    },
  });
});

app.listen(port, 'localhost', () => {
  console.log(`Listening on localhost:${port}`);
});

路由处理程序(/stored-objects)

import express from 'express';

const router = express.Router();

router.put('/:id', (req, res, next) => {
  console.debug(`PUT stored-objects`, { params: req.params });
  if (req.body instanceof Buffer) {
    console.debug(
      'IN PUT route, buffer size - no shit - ',
      req.body.byteLength
    );
  }
  res.json({"status":"OK"});
});
解决方法

问题出在中间件的加载顺序上:

  • 你先加载了express.raw,但之后又加载了express.json()中间件。当请求进入时,express.raw已经把请求体解析成Buffer,但后续的express.json()会尝试重新解析这个Buffer——由于二进制数据不是合法JSON,解析失败后会把req.body重置为无效或截断后的数据。

修复步骤:

  1. 调整中间件顺序,把express.json()和express.urlencoded()移到express.raw之前。这样JSON类型的请求会被express.json()优先处理,二进制请求则跳过JSON解析,留给express.raw处理。
  2. 确保express.raw的type判断逻辑正确,避免和其他解析中间件的处理范围重叠。

修改后的主应用中间件顺序示例:

app.use(cors());
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(
  express.raw({
    type: (req) => {
      const contentType = req.headers['content-type'];
      console.debug(`Got content type ${contentType}`);
      if (
        contentType !== 'application/json' &&
        !contentType?.startsWith('text/')
      ) {
        return true;
      }
      return false;
    },
    limit: '1GB',
  })
);
app.use(
  mung.json((body, _req, res) => {
    console.debug('Munging json()');
    if (res.statusCode < 300) {
      body = { result: body };
    }
    return body;
  })
);
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));

注:mung.json()仅处理JSON响应,不会影响请求体解析,所以位置放在express.raw之后不影响结果。

内容的提问来源于stack exchange,提问作者Aurelia Peters

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 07:14:56