【问题标题】:How can I create a error handler middleware in express using Typescript如何使用 Typescript 在 express 中创建错误处理程序中间件
【发布时间】:2022-10-06 07:53:17
【问题描述】:

通过使用 Express 和 TypeScript,我试图创建一个中间件来捕获像 Sentry 这样的错误,代码如下:

 const catchError = (
  error: Error,
  req: Request,
  _res: Response,
  next: any
) => {
   console.log(\"ERROR: \", error);
   //some logic

  next(error);
}

索引.ts

  app.use(bodyParser.json({ limit }));
  app.use(morgan(\"[:date[iso]] :method :url :status :response-time ms\"));

  app.use(express.json());
  app.use(cors({ credentials: true, origin: true }));

  app.use(bodyParser.urlencoded({ extended: false }));
//controllers

app.use(catchError as express.ErrorRequestHandler)

为什么我的中间件只有在我输入时才能工作:

} catch (error) { 
   next(error);
}

在一个有错误的函数中,没有它就不能工作?这个中间件还应该在不使用next(error) 的情况下捕获错误和异常。

标签: javascript node.js typescript express


【解决方案1】:
  1. 首先,您需要创建一个自定义 Error 类来扩展 Base Error 类
  2. 您必须使类灵活,以便能够接受您可能希望传递的错误代码
  3. 创建中间件来处理错误。 至于我的,我已经设置了一个可以处理一些密码验证和猫鼬错误的设备。希望您也可以扩展此处的功能以满足您的需求

    扩展基本错误的自定义错误类

    interface IErrorResponse {
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        [prop: string | symbol]: any
        statusCode?: number
        message: string
        code?: number
    }
    
    class ErrorResponse extends Error implements IErrorResponse {
        public statusCode: number;
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        [prop: string]: any
        constructor(message: string, statusCode: number) {
            super(message)
            this.statusCode = statusCode
        }
    }
    
    export default ErrorResponse
    

    中间件

    /* eslint-disable @typescript-eslint/no-explicit-any */
    /* eslint-disable @typescript-eslint/no-unused-vars */
    import { Request, Response, NextFunction } from "express"
    import capitalize from "../utils/capitalize"
    import ErrorResponse from "./ErrorResponse"
    
    export default function (
        err: ErrorResponse,
        req: Request,
        res: Response,
        next: NextFunction,
    ): Response<any, Record<string, any>> {
        let error: ErrorResponse&{[key:string]:any} = { ...err }
        error.message = err.message
        // console.log(err)
        if (err.code === 11000) {
            const message = Object.keys(err).map((k) =>
                capitalize(`${k} already exist`),
            )
            error = new ErrorResponse(String(message), 400)
        }
        if (err.name === "ValidationError") {
            const message = Object.keys(err).map(function (value) {
                // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
                return typeof value === "object" ? error["message"] : value
            })
            console.log("Parsing ", message)
    
            error = new ErrorResponse(String(message), 400)
        }
    
        if (error.message.split(/\n/).length > 1) {
            return res.status(error.statusCode || 500).json({
                success: false,
                message:
                    error.message
                        .replace(/\t/, "")
                        .split("\n")
                        .filter((e) => e !== "") || "Internal server error",
            })
        }
        return res.status(error.statusCode || 500).json({
            success: false,
            message: error.message || "Internal server error",
        })
    }
    

    在这种情况下,可能这些是您可以捕捉到的错误 我有这个密码验证器,它确实在错误上附加了一些字符串,并以\n 终止每个错误,因此错误处理程序能够拆分错误并以JSON 格式给我一个错误列表

    passwordRegex = function ({
            props,
            fields,
        }: {
            props: { [x: string]: string },
            fields: { fieldName: string, name: string }[],
        }): { passOK: boolean, errors: string } {
            let errors = ""
            try {
                for (let key of Object.keys(props)) {
                    if (fields.some((f) => f.fieldName === key)) {
                        const regex = new RegExp(props[key], "i")
                        const field = fields.find((f) => f.fieldName === key)
                        if (regex.test(props!["password"])) {
                            errors += `Password should not contain your ${field!.name}\n`
                        }
                    }
                }
                if (!/[a-z]/.test(props["password"])) {
                    errors += "Password must contain at least 1 lowercase letter\n"
                }
                if (!/[A-Z]/.test(props["password"])) {
                    errors += "Password must contain at least 1 uppercase letter\n"
                }
                if (!/[0-9]/.test(props["password"])) {
                    errors += "Password must contain at least a number\n"
                }
                if (!/[\w]{7,16}/.test(props["password"])) {
                    errors += "Password must be at least 8 characters long\n"
                }
                if (/[.*+?^${}#%^@!`()|[\]\\]{4,}/.test(props["password"])) {
                    errors +=
                        "Password must not contain more than 4 repeating characters\n"
                }
                if (!/[.*+?^${}#%^@!`()|[\]\\]/.test(props["password"])) {
                    errors +=
                        "Password must be at least 1 special character (.*+?^${}#%^@!`())\n"
                }
                if (errors !== "") {
                    return { passOK: false, errors }
                }
                return { passOK: true, errors }
            } catch (err) {
                return { passOK: false, errors }
            }
        }
    

    我如何将其作为中间件传递?

    export default ({ app }:{app:Application}) => {
        app.use(ExpressError)
    }
    
    

    传递错误状态

    const { passOK, errors } = passwordUtils.passwordRegex({
                    props: req.body,
                    fields: [
                        { fieldName: "firstName", name: "First name" },
                        { fieldName: "lastName", name: "Last name" },
                        { fieldName: "email", name: "Email" },
                    ],
                })
    
                if (!passOK) {
                    return next(new ErrorResponse(errors, 400))
                }
    

    希望这有助于回答您的问题以自定义您的错误 我刚刚给出了一个概述,但您可以继续检查错误的确切代码和值以确定错误类型并返回适当的错误消息或在某处​​记录

【讨论】:

    猜你喜欢
    • 2021-04-29
    • 2019-10-10
    • 2021-04-14
    • 1970-01-01
    • 1970-01-01
    • 2021-02-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多