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

chore: improves errors handling

e22m4u 2 месяцев назад
Родитель
Сommit
4efa464fd7
4 измененных файлов с 67 добавлено и 41 удалено
  1. 17 15
      dist/cjs/index.cjs
  2. 5 0
      src/senders/error-sender.js
  3. 24 26
      src/trie-router.js
  4. 21 0
      src/trie-router.spec.js

+ 17 - 15
dist/cjs/index.cjs

@@ -1027,6 +1027,11 @@ var _ErrorSender = class _ErrorSender extends DebuggableService {
     };
     console.warn((0, import_util.inspect)(requestData, inspectOptions));
     console.warn((0, import_util.inspect)(body, inspectOptions));
+    if (error.stack) {
+      console.log(error.stack);
+    } else {
+      console.error(error);
+    }
     res.statusCode = statusCode;
     res.setHeader("content-type", "application/json; charset=utf-8");
     res.end(JSON.stringify(body, null, 2), "utf-8");
@@ -1607,16 +1612,16 @@ var _TrieRouter = class _TrieRouter extends DebuggableService {
       const context = new RequestContext(container, req, res);
       container.set(RequestContext, context);
       context.params = params;
-      const reqDataOrPromise = this.getService(RequestParser).parse(req);
-      if (isPromise(reqDataOrPromise)) {
-        const reqData = await reqDataOrPromise;
-        Object.assign(context, reqData);
-      } else {
-        Object.assign(context, reqDataOrPromise);
-      }
-      let data, error;
-      const hookInvoker = this.getService(HookInvoker);
+      let data;
       try {
+        const reqDataOrPromise = this.getService(RequestParser).parse(req);
+        if (isPromise(reqDataOrPromise)) {
+          const reqData = await reqDataOrPromise;
+          Object.assign(context, reqData);
+        } else {
+          Object.assign(context, reqDataOrPromise);
+        }
+        const hookInvoker = this.getService(HookInvoker);
         data = hookInvoker.invokeAndContinueUntilValueReceived(
           route,
           HookType.PRE_HANDLER,
@@ -1638,14 +1643,11 @@ var _TrieRouter = class _TrieRouter extends DebuggableService {
             postHandlerData = await postHandlerData;
           if (postHandlerData != null) data = postHandlerData;
         }
-      } catch (err) {
-        error = err;
-      }
-      if (error) {
+      } catch (error) {
         this.getService(ErrorSender).send(req, res, error);
-      } else {
-        this.getService(DataSender).send(res, data);
+        return;
       }
+      this.getService(DataSender).send(res, data);
     }
   }
   /**

+ 5 - 0
src/senders/error-sender.js

@@ -54,6 +54,11 @@ export class ErrorSender extends DebuggableService {
     };
     console.warn(inspect(requestData, inspectOptions));
     console.warn(inspect(body, inspectOptions));
+    if (error.stack) {
+      console.log(error.stack);
+    } else {
+      console.error(error);
+    }
     res.statusCode = statusCode;
     res.setHeader('content-type', 'application/json; charset=utf-8');
     res.end(JSON.stringify(body, null, 2), 'utf-8');

+ 24 - 26
src/trie-router.js

@@ -95,27 +95,28 @@ export class TrieRouter extends DebuggableService {
       // так как они были определены в момент
       // поиска подходящего роута
       context.params = params;
-      // разбор тела, заголовков и других данных
-      // запроса выполняется отдельным сервисом,
-      // после чего результат записывается
-      // в контекст передаваемый обработчику
-      const reqDataOrPromise = this.getService(RequestParser).parse(req);
-      // результат разбора может являться асинхронным,
-      // и вместо того, что бы разрывать поток выполнения,
-      // стоит проверить, действительно ли необходимо
-      // использование оператора "await"
-      if (isPromise(reqDataOrPromise)) {
-        const reqData = await reqDataOrPromise;
-        Object.assign(context, reqData);
-      } else {
-        Object.assign(context, reqDataOrPromise);
-      }
-      // получение данных от обработчика, который
-      // находится в найденном роуте, и отправка
-      // результата в качестве ответа сервера
-      let data, error;
-      const hookInvoker = this.getService(HookInvoker);
+      // при разборе входящих данных и выполнении обработчиков
+      // запроса, требуется перехватывать возможные ошибки
+      // для корректной отправки сервисом ErrorSender
+      let data;
       try {
+        // разбор тела, заголовков и других данных запроса
+        // выполняется отдельным сервисом, после чего результат
+        // записывается в контекст передаваемый обработчику
+        const reqDataOrPromise = this.getService(RequestParser).parse(req);
+        // результат разбора может являться асинхронным, и вместо
+        // того, что бы разрывать поток выполнения, стоит проверить,
+        // действительно ли необходимо использование оператора "await"
+        if (isPromise(reqDataOrPromise)) {
+          const reqData = await reqDataOrPromise;
+          Object.assign(context, reqData);
+        } else {
+          Object.assign(context, reqDataOrPromise);
+        }
+        // получение данных от обработчика, который находится
+        // в найденном маршруте, и отправка результата в качестве
+        // ответа сервера
+        const hookInvoker = this.getService(HookInvoker);
         // если результатом вызова хуков "preHandler" является
         // значение (или Promise) отличное от "undefined" и "null",
         // то такое значение используется в качестве ответа
@@ -146,14 +147,11 @@ export class TrieRouter extends DebuggableService {
             postHandlerData = await postHandlerData;
           if (postHandlerData != null) data = postHandlerData;
         }
-      } catch (err) {
-        error = err;
-      }
-      if (error) {
+      } catch (error) {
         this.getService(ErrorSender).send(req, res, error);
-      } else {
-        this.getService(DataSender).send(res, data);
+        return;
       }
+      this.getService(DataSender).send(res, data);
     }
   }
 

+ 21 - 0
src/trie-router.spec.js

@@ -472,6 +472,27 @@ describe('TrieRouter', function () {
       const res = createResponseMock();
       router.requestListener(req, res);
     });
+
+    it('should send parsing error response instead of throwing error', async function () {
+      const router = new TrieRouter();
+      router.defineRoute({
+        method: HttpMethod.POST,
+        path: '/',
+        handler() {},
+      });
+      const req = createRequestMock({
+        method: HttpMethod.POST,
+        headers: {'content-type': 'application/json'},
+        body: 'invalid json',
+      });
+      const res = createResponseMock();
+      router.requestListener(req, res);
+      const body = await res.getBody();
+      expect(res.statusCode).to.be.eq(400);
+      expect(JSON.parse(body)).to.be.eql({
+        error: {message: 'Unable to parse request body.'},
+      });
+    });
   });
 
   describe('addHook', function () {