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 i18n và trướ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ả
messageCóMô 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