我正在对我创建的node.js api 进行性能测试。
有一个 POST 端点,它将图像作为 base64 的输入。所以请求有效负载相当大,我的测试用例图像约为 7-8mb。
当我同时对 10 个用户运行性能测试时,出现以下错误:
请求:
{"log_id":"db0ac1d0-cafe-11e9-afec-e91ff7e323e3","level":"info","request":{"method":"POST","path":"<removed>","url":"<api_url_removed>","body":{},"forward_for":"<removed>","content_type":"application/json","content_length":"7687038"},"message":"Received","log_type":"request","timestamp":"2019-08-30 08:19:15"}
错误:
BadRequestError:请求中止 在 IncomingMessage.onAborted (/app/node_modules/raw-body/index.js:231:10) 在 IncomingMessage.emit (events.js:189:13) 在 abortIncoming (_http_server.js:449:9) 在 socketOnClose (_http_server.js:442:3) 在 Socket.emit (events.js:194:15) 在 TCP._handle.close (net.js:600:12)
我可以看到其中 10-20 个请求出现相同的错误。他们都有独特的 ID。显然,因为我正在运行性能测试,所以发出这么多请求是正常的。
我的问题是为什么 node.js/express 会抛出这个 BadRequestError 以及我该如何处理它。
app.ts
class App {
public app: express.Application;
public config: any;
public log = Logger;
constructor() {
this.app = express();
this.errors();
this.environment();
this.database();
this.middleware();
this.routes();
}
private environment(): void {
this.config = new Config();
}
private errors(): void {
// TODO: Remove ( Handled By Winston );
// process.on("uncaughtException", (ex) => {
// process.exit(1);
// });
process.on("unhandledRejection", (ex) => {
throw ex;
});
}
private database(): void {
const uri: string = this.config.db.uri;
const options: mongoose.ConnectionOptions = this.config.db.options;
mongoose.connect(uri, options).then(
() => {
this.log.info("MongoDB Successfully Connected On: " + this.config.db.uri);
},
(err: any) => {
this.log.error("MongoDB Error:", err);
this.log.info("%s MongoDB connection error. Please make sure MongoDB is running.");
throw err;
},
);
}
private middleware(): void {
const logs = new LogMiddleware(this.app);
this.app.use(cors());
this.app.use(morgan("combined", {
skip: (req, res) => {
return (req.originalUrl === "/api/v2/healthcheck") ? true : false;
},
stream: {
write: (meta: any) => {
},
},
}));
this.app.use(express.json({limit: "16mb"}));
this.app.use(express.urlencoded({ limit: "16mb", extended: true, parameterLimit: 50000 }));
this.app.use(passport.initialize());
}
private routes(): void {
const routes = new Routes(this.app);
}
}
export default App;
当客户端在服务器处理完请求之前断开连接时,Node.js 和 Express 中通常会发生
BadRequestError: request aborted
错误。发生这种情况的原因有多种,处理方法如下:
网络问题
如果客户端的网络连接不稳定或中断,请求可能会在到达服务器之前被中止。确保您的网络连接稳定。
请求大小和正文解析
如果您使用
body-parser
或其他中间件,则可能会出现处理大负载的问题。尝试增加请求正文限制以处理更大的负载:
const express = require('express');
const bodyParser = require('body-parser');
const app = express();
// Increase limit as needed
app.use(bodyParser.json({ limit: '10mb' }));
app.use(bodyParser.urlencoded({ extended: true, limit: '10mb' }));
优雅地处理中止的请求
添加事件侦听器来处理中止的请求,这样它们就不会导致未捕获的错误:
app.use((req, res, next) => {
req.on('aborted', () => {
console.error('Request was aborted by the client');
});
next();
});
反向代理超时(如果适用)
如果您使用 Nginx 等反向代理,如果请求时间过长或超出有效负载大小限制,它可能会终止连接。检查您的代理设置以确保它们不会导致请求中止。
此问题与 body-parser 包设置有关
这是文档中提到的基本设置
var express = require('express')
var bodyParser = require('body-parser')
var app = express()
// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: false }))
// parse application/json
app.use(bodyParser.json())
app.use(function (req, res) {
res.setHeader('Content-Type', 'text/plain')
res.write('you posted:\n')
res.end(JSON.stringify(req.body, null, 2))
})
您还可以在此处找到代码的链接添加通用 JSON 和 URL 编码
我认为您希望应用程序以以下方式启动:
this.app = express();
this.errors();
this.environment();
this.database();
this.middleware();
this.routes();
Node.js 具有异步特性,数据库连接进行 I/O 操作时会执行最后一次操作。在建立数据库连接之前,您的应用程序很可能已经开始处理请求。因此,在某些控制器/路由中,您会抛出 400 错误。
您需要做的是在连接并运行所有烘焙服务(例如数据库)后启动应用程序。