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

启用express-mongo-sanitize时报错:无法赋值只读属性'query'

问题:启用express-mongo-sanitize后出现只读属性赋值错误

这是基于MEAN栈构建的Web应用,运行环境为Node.js 20.18、Ubuntu 22.04、Angular 17.x(Angular的dist文件由Node项目托管)。访问应用URL时抛出错误,注释掉app.js中的app.use(mongoSanitize())后错误消失,但相同代码在另一台配置一致的VPS上运行正常,无法定位问题原因。


核心错误信息

TypeError: Cannot assign to read only property 'query' of object '#<IncomingMessage>'
    at /root/cops/node_modules/express-mongo-sanitize/index.js:113:18

app.js代码片段

const path = require("path")
const mongoose = require('mongoose');
const express = require('express');
const bodyparser = require('body-parser');
const cookieParser = require('cookie-parser');
const crypto = require('crypto');

const { xss } = require('express-xss-sanitizer');
const helmet = require('helmet');
const mongoSanitize = require('express-mongo-sanitize');

const config = require('./config/config');
const morgan = require('./config/morgan');
const logger = require('./config/logger');
const ApiError = require('./helpers/ApiError');
const { errorHandlerNew, errorConvertor } = require('./middleware/errors');
const app = express();

app.use(morgan.successLogHandler);
app.use(morgan.errorLogHandler);

const connectStr = config.dbConnection + config.dbName;
mongoose.connect(connectStr, mongooseOpts)
  .then(() => {
    logger.info('Connected to database');
  })
  .catch((err) => {
    logger.error('Database connection failed with error: ' + err);
  });

app.use(bodyparser.json());
app.use(bodyparser.urlencoded({extended: false}));
app.use(cookieParser());

app.use(xss());
// app.use(mongoSanitize());   /// WHEN ENABLED GIVES ERROR

app.use("/", express.static(path.join(__dirname, "angular")));

const myCors = {
  origin: ["http://localhost:4200","http://localhost:5200", ...],
  default: "http://localhost:4200"
}

app.use((req, res, next) => {
  // logger.info('app.js req.headers.origin: ' + req.headers.origin);
  let reqHeadersOrigin = '';
  if(req.headers.origin) reqHeadersOrigin = req.headers.origin.toLowerCase();
  const origin = myCors.origin.includes(reqHeadersOrigin) ? req.headers.origin : myCors.default;
  res.setHeader('Access-Control-Allow-Origin', origin);
  res.setHeader("Access-Control-Allow-Credentials", true);
  res.setHeader(
  'Access-Control-Allow-Headers',
  'Origin, X-Requested-With, Content-Type, Accept, Authorization, x-client-key, x-client-token, x-client-secret');

  res.setHeader(
  'Access-Control-Allow-Methods',
  'GET, POST, PUT, PATCH, DELETE, OPTIONS')

  if (req.method === 'OPTIONS') {
    return res.status(200).end();
  }

  next();
});

app.use((req, res, next) => {
  res.sendFile(path.join(__dirname, "angular", "index.html"));
});

加载门户时的完整错误日志

10 Jan 2025, 10:47:06 pm: error: TypeError: Cannot assign to read only property 'query' of object '#<IncomingMessage>'
    at /root/cops/node_modules/express-mongo-sanitize/index.js:113:18
    at Array.forEach (<anonymous>)
    at /root/cops/node_modules/express-mongo-sanitize/index.js:110:44
    at Layer.handle [as handle_request] (/root/cops/node_modules/express/lib/router/layer.js:95:5)
    at trim_prefix (/root/cops/node_modules/express/lib/router/index.js:328:13)
    at /root/cops/node_modules/express/lib/router/index.js:286:9
    at Function.process_params (/root/cops/node_modules/express/lib/router/index.js:346:12)
    at next (/root/cops/node_modules/express/lib/router/index.js:280:10)
    at /root/cops/node_modules/express-xss-sanitizer/index.js:19:5
    at Layer.handle [as handle_request] (/root/cops/node_modules/express/lib/router/layer.js:95:5)
    at trim_prefix (/root/cops/node_modules/express/lib/router/index.js:328:13)
    at /root/cops/node_modules/express/lib/router/index.js:286:9
    at Function.process_params (/root/cops/node_modules/express/lib/router/index.js:346:12)
    at next (/root/cops/node_modules/express/lib/router/index.js:280:10)
    at cookieParser (/root/cops/node_modules/cookie-parser/index.js:57:14)
    at Layer.handle [as handle_request] (/root/cops/node_modules/express/lib/router/layer.js:95:5)
    at trim_prefix (/root/cops/node_modules/express/lib/router/index.js:328:13)
    at /root/cops/node_modules/express/lib/router/index.js:286:9
    at Function.process_params (/root/cops/node_modules/express/lib/router/index.js:346:12)
    at next (/root/cops/node_modules/express/lib/router/index.js:280:10)
    at urlencodedParser (/root/cops/node_modules/body-parser/lib/types/urlencoded.js:94:7)
    at Layer.handle [as handle_request] (/root/cops/node_modules/express/lib/router/layer.js:95:5)

错误截图

错误截图


可能的原因与解决办法

  1. 依赖版本不一致
    两台VPS配置看似一致,但实际依赖包版本可能存在差异。express-mongo-sanitize旧版本在Node.js 20+环境下,会尝试修改Express请求对象的只读query属性,触发报错。

    • 执行npm list express-mongo-sanitize对比两台机器的版本,将问题机器的包升级到最新稳定版:
      npm install express-mongo-sanitize@latest
      
  2. Express版本兼容性
    Node.js 20对对象属性的只读限制更严格,旧版Express的请求对象query属性可能被设为只读,导致中间件无法修改。

    • 升级Express到兼容版本:
      npm install express@latest
      
  3. 调整中间件顺序
    当前代码中mongoSanitize放在xss之后,尝试将其移到bodyparser之后、xss之前,避免中间件修改请求对象的顺序冲突:

    app.use(bodyparser.json());
    app.use(bodyparser.urlencoded({extended: false}));
    app.use(cookieParser());
    app.use(mongoSanitize()); // 调整到xss之前
    app.use(xss());
    
  4. 使用配置选项避免修改原对象
    启用express-mongo-sanitize的replaceWith选项,不直接修改原query对象,而是返回 sanitize 后的新对象:

    app.use(mongoSanitize({
      replaceWith: '_'
    }));
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 02:33:10