Просмотр исходного кода

fix(core): Correctly handle 404 and other Nestjs errors

The custom ExceptionLoggerFilter was swallowing Nestjs errors, e.g. 404 errors. Now we log them and return the appropriate response.

Closes #187
Michael Bromley 6 лет назад
Родитель
Сommit
4f2c4dfc3b

+ 4 - 4
packages/core/src/api/common/parse-context.ts

@@ -1,4 +1,4 @@
-import { ExecutionContext } from '@nestjs/common';
+import { ArgumentsHost, ExecutionContext } from '@nestjs/common';
 import { GqlExecutionContext } from '@nestjs/graphql';
 import { Request, Response } from 'express';
 import { GraphQLResolveInfo } from 'graphql';
@@ -8,10 +8,10 @@ import { GraphQLResolveInfo } from 'graphql';
  * GraphQL & REST requests.
  */
 export function parseContext(
-    context: ExecutionContext,
+    context: ExecutionContext | ArgumentsHost,
 ): { req: Request; res: Response; isGraphQL: boolean; info?: GraphQLResolveInfo } {
-    const graphQlContext = GqlExecutionContext.create(context);
-    const restContext = GqlExecutionContext.create(context);
+    const graphQlContext = GqlExecutionContext.create(context as ExecutionContext);
+    const restContext = GqlExecutionContext.create(context as ExecutionContext);
     const info = graphQlContext.getInfo();
     let req: Request;
     let res: Response;

+ 22 - 2
packages/core/src/api/middleware/exception-logger.filter.ts

@@ -1,13 +1,15 @@
-import { ArgumentsHost, ExceptionFilter } from '@nestjs/common';
+import { ArgumentsHost, ExceptionFilter, HttpException } from '@nestjs/common';
+import { Request, Response } from 'express';
 
 import { Logger, LogLevel } from '../../config';
 import { I18nError } from '../../i18n/i18n-error';
+import { parseContext } from '../common/parse-context';
 
 /**
  * Logs thrown I18nErrors via the configured VendureLogger.
  */
 export class ExceptionLoggerFilter implements ExceptionFilter {
-    catch(exception: Error, host: ArgumentsHost) {
+    catch(exception: Error | HttpException | I18nError, host: ArgumentsHost) {
         if (exception instanceof I18nError) {
             const { code, message, logLevel } = exception;
             const logMessage = `${code || 'Error'}: ${message}`;
@@ -28,6 +30,24 @@ export class ExceptionLoggerFilter implements ExceptionFilter {
                     Logger.verbose(logMessage);
                     break;
             }
+        } else if (exception instanceof HttpException) {
+            // Handle other Nestjs errors
+            const { req, res, info } = parseContext(host);
+            const status = exception.getStatus();
+            let message = exception.message;
+            let stack = exception.stack;
+            if (status === 404) {
+                message = exception.message.message;
+                stack = undefined;
+            }
+            Logger.error(message, undefined, stack);
+
+            res.status(status).json({
+                statusCode: status,
+                message,
+                timestamp: new Date().toISOString(),
+                path: req.url,
+            });
         }
     }
 }

+ 13 - 5
packages/core/src/config/logger/default-logger.ts

@@ -81,27 +81,31 @@ export class DefaultLogger implements VendureLogger {
 
     error(message: string, context?: string, trace?: string | undefined): void {
         if (this.level >= LogLevel.Error) {
-            this.logMessage(chalk.red(`error`), chalk.red(message + (trace ? `\n${trace}` : '')), context);
+            this.logMessage(
+                chalk.red(`error`),
+                chalk.red(this.ensureString(message) + (trace ? `\n${trace}` : '')),
+                context,
+            );
         }
     }
     warn(message: string, context?: string): void {
         if (this.level >= LogLevel.Warn) {
-            this.logMessage(chalk.yellow(`warn`), chalk.yellow(message), context);
+            this.logMessage(chalk.yellow(`warn`), chalk.yellow(this.ensureString(message)), context);
         }
     }
     info(message: string, context?: string): void {
         if (this.level >= LogLevel.Info) {
-            this.logMessage(chalk.blue(`info`), message, context);
+            this.logMessage(chalk.blue(`info`), this.ensureString(message), context);
         }
     }
     verbose(message: string, context?: string): void {
         if (this.level >= LogLevel.Verbose) {
-            this.logMessage(chalk.magenta(`verbose`), message, context);
+            this.logMessage(chalk.magenta(`verbose`), this.ensureString(message), context);
         }
     }
     debug(message: string, context?: string): void {
         if (this.level >= LogLevel.Debug) {
-            this.logMessage(chalk.magenta(`debug`), message, context);
+            this.logMessage(chalk.magenta(`debug`), this.ensureString(message), context);
         }
     }
 
@@ -123,4 +127,8 @@ export class DefaultLogger implements VendureLogger {
             return '';
         }
     }
+
+    private ensureString(message: string | object | any[]): string {
+        return typeof message === 'string' ? message : JSON.stringify(message, null, 2);
+    }
 }