Skip to content

Commit 678cb86

Browse files
committed
Merge branch 'Elassyo-fix-double-exec' into next
2 parents 98e46b9 + 9e8b03a commit 678cb86

File tree

2 files changed

+28
-8
lines changed

2 files changed

+28
-8
lines changed

src/driver/express/ExpressDriver.ts

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -160,20 +160,28 @@ export class ExpressDriver extends BaseDriver {
160160
// prepare route and route handler function
161161
const route = ActionMetadata.appendBaseRoute(this.routePrefix, actionMetadata.fullRoute);
162162
const routeHandler = function routeHandler(request: any, response: any, next: Function) {
163-
// Express calls the "get" route automatically when we call the "head" route:
164-
// Reference: https://expressjs.com/en/4x/api.html#router.METHOD
165-
// This causes a double action execution on our side, which results in an unhandled rejection,
166-
// saying: "Can't set headers after they are sent".
167-
// The following line skips action processing when the request method does not match the action method.
168-
if (actionMetadata.type !== "all" && request.method.toLowerCase() !== actionMetadata.type)
169-
return next();
170-
171163
return executeCallback({request, response, next});
172164
};
173165

166+
// This ensures that a request is only processed once to prevent unhandled rejections saying
167+
// "Can't set headers after they are sent"
168+
// Some examples of reasons a request may cause multiple route calls:
169+
// * Express calls the "get" route automatically when we call the "head" route:
170+
// Reference: https://expressjs.com/en/4x/api.html#router.METHOD
171+
// This causes a double execution on our side.
172+
// * Multiple routes match the request (e.g. GET /users/me matches both @All(/users/me) and @Get(/users/:id)).
173+
// The following middleware only starts an action processing if the request has not been processed before.
174+
const routeGuard = function routeGuard(request: any, response: any, next: Function) {
175+
if (!request.routingControllersStarted) {
176+
request.routingControllersStarted = true;
177+
return next();
178+
}
179+
};
180+
174181
// finally register action in express
175182
this.express[actionMetadata.type.toLowerCase()](...[
176183
route,
184+
routeGuard,
177185
...beforeMiddlewares,
178186
...defaultMiddlewares,
179187
routeHandler,

src/driver/koa/KoaDriver.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,9 +132,21 @@ export class KoaDriver extends BaseDriver {
132132
return executeCallback(options);
133133
};
134134

135+
// This ensures that a request is only processed once. Multiple routes may match a request
136+
// e.g. GET /users/me matches both @All(/users/me) and @Get(/users/:id)), only the first matching route should
137+
// be called.
138+
// The following middleware only starts an action processing if the request has not been processed before.
139+
const routeGuard = (context: any, next: () => Promise<any>) => {
140+
if (!context.request.routingControllersStarted) {
141+
context.request.routingControllersStarted = true;
142+
return next();
143+
}
144+
};
145+
135146
// finally register action in koa
136147
this.router[actionMetadata.type.toLowerCase()](...[
137148
route,
149+
routeGuard,
138150
...beforeMiddlewares,
139151
...defaultMiddlewares,
140152
routeHandler,

0 commit comments

Comments
 (0)