Bỏ qua, đến nội dung

Cài đặt và sử dụng — Error Handler

Tổng quan

Plugin plugin-error-handler là middleware xử lý lỗi tập trung cho toàn bộ HTTP request pipeline. Mọi exception không được xử lý sẽ bị bắt, phân loại và trả về response lỗi chuẩn hóa cho client.

Yêu cầu

Thành phầnYêu cầu
Server DigiforcePhiên bản >= 1.0

Quan trọng

Đây là plugin core — không nên tắt. Nhiều plugin khác phụ thuộc vào error handler để đăng ký xử lý lỗi riêng (ví dụ: plugin-departments, plugin-data-source-rest-api).

Bước 1: Xác nhận plugin đã bật

Plugin thường được bật sẵn. Kiểm tra trong Settings → Plugin Manager → tìm plugin-error-handler.

Cơ chế hoạt động

Vị trí trong Middleware Chain

Plugin đăng ký middleware sau i18ntrước cors:

i18n → errorHandler → cors → auth → acl → handler

Vị trí này đảm bảo:

  • Có thể sử dụng ctx.i18n.t() để dịch thông báo lỗi (nhờ nằm sau i18n)
  • Bắt được lỗi từ tất cả middleware downstream (cors, auth, acl, handler)

Luồng xử lý lỗi

Đăng ký handler

Plugin sử dụng pattern guard + render:

typescript
errorHandler.register(
  (err) => boolean,          // guard: kiểm tra lỗi có thuộc loại này không
  (err, ctx) => void         // render: xử lý và tạo response
);

Khi lỗi xảy ra, plugin duyệt danh sách handler theo thứ tự đăng ký. Handler đầu tiên có guard trả về true sẽ được sử dụng. Nếu không có handler nào khớp, defaultHandler được gọi.

Các loại lỗi được xử lý

1. Sequelize Validation Error

Phát hiện: err.name === 'SequelizeValidationError'

Xử lý:

  • Duyệt qua err.errors (mảng lỗi validation)
  • Tìm tên trường trong collection schema (uiSchema.title)
  • Dịch thông báo lỗi qua i18n
  • Trả về HTTP 400

Response:

json
{
  "errors": [
    { "message": "Trường 'Email' phải là duy nhất" },
    { "message": "Trường 'Tên' không được để trống" }
  ]
}

2. Unique Constraint Error

Phát hiện: err.name === 'SequelizeUniqueConstraintError'

Xử lý: Tương tự Validation Error — phân tích constraint name để xác định trường bị trùng lặp, dịch thông báo, trả HTTP 400.

3. SQL Syntax Error

Phát hiện theo database:

DatabaseĐiều kiện
MySQL / MariaDBerr.errno === 1064
PostgreSQLerr.code === '42601'
SQLiteerr.code === 'SQLITE_ERROR' + message chứa "syntax error"

Xử lý: Trả về thông báo chung "Invalid SQL syntax" (không lộ chi tiết schema). HTTP 500.

4. SQL Reference Error (Invalid Column/Table)

Phát hiện theo database:

DatabaseLỗiĐiều kiện
MySQLUnknown columnerrno 1054
MySQLUnknown tableerrno 1051, 1146
MySQLAmbiguous columnerrno 1052
PostgreSQLUnknown columncode '42703'
PostgreSQLUnknown tablecode '42P01'
PostgreSQLAmbiguous columncode '42702'
SQLiteUnknown column/tableMessage pattern matching

Xử lý: Trả về "Invalid SQL column or table reference". HTTP 400.

5. Lỗi mặc định (Default Handler)

Mọi lỗi không khớp với handler nào sẽ được xử lý bởi defaultHandler:

typescript
ctx.status = err.statusCode || err.status || 500;
ctx.body = {
  errors: [{
    message: err.message,
    code: err.code,
    title: err.title,  // nếu có
  }],
};

Nếu lỗi có cause, message sẽ được nối thêm: "message: cause.message".

Đăng ký Custom Error Handler

Các plugin khác có thể đăng ký handler riêng:

typescript
// Ví dụ từ plugin-departments
const errorHandlerPlugin = this.app.pm.get<PluginErrorHandler>('error-handler');
errorHandlerPlugin.errorHandler.register(
  (err) => err.message === "Invalid main department...",
  (err, ctx) => {
    ctx.throw(400, ctx.i18n.t("Invalid main department...", { ns: 'departments' }));
  },
);

// Ví dụ từ plugin-data-source-rest-api
errorHandlerPlugin.errorHandler.register(
  (err) => err.cause?.errorContent !== undefined,
  (err, ctx) => {
    ctx.status = 500;
    ctx.body = { errors: [{ message: String(err.cause.errorContent) }] };
  },
);

Response Format chuẩn

Mọi response lỗi tuân theo format:

json
{
  "errors": [
    {
      "message": "Mô tả lỗi",
      "code": "MÃ_LỖI",
      "title": "Tiêu đề lỗi"
    }
  ]
}
TrườngBắt buộcMô tả
messageMô tả lỗi (có thể được dịch qua i18n)
codeKhôngMã lỗi nội bộ
titleKhôngTiêu đề lỗi

Logging

Mọi lỗi đều được ghi log trước khi render response:

typescript
ctx.log.error(err.message, {
  method: 'error-handler',
  err: err.stack,
  cause: err.cause,
});

Điều này đảm bảo thông tin lỗi đầy đủ (bao gồm stack trace) được lưu trong log system, ngay cả khi client chỉ nhận thông báo chung.

Lưu ý

  • Plugin không tạo API endpoint hay database table
  • Lỗi 500 chỉ trả thông báo chung cho client — chi tiết nằm trong log server
  • Lỗi validation (400) trả về chi tiết trường bị lỗi
  • Handler được duyệt theo thứ tự đăng ký — handler đầu tiên khớp sẽ được sử dụng
  • Plugin khác nên đăng ký handler trong beforeLoad() hoặc load() để đảm bảo sẵn sàng