在使用Node.js和Express创建一些端点时,我遇到了一段代码,它在不同端点上的同一控制器文件中重复了几次.此代码位于TRY…CATCH块内的条件中,它用于验证数据库中是否存在已发送的参数,因此,如果存在,则相应地继续执行.以下是我的原始代码:

const productListing = async (req, res) => {
    const { category_id } = req.query;
    try {
        // if there are query params execute this if statement
        if (req.url.includes("?")) {
            // the next 3 lines of code repeat a few times throughout the controller

            const validCategory = await knex("categories").where("id", category_id)
            if (validCategory.length === 0) {
                return res.status(404).json({ "message": "Category not found" });
            };

            const productsByCategory = await knex("products").where({ category_id })
            return res.status(200).json(productsByCategory);
        }; 

        const allProducts = await knex("products")
        return res.status(200).json(allProducts);
    } catch (error) {
        return res.status(500).json({ "message": "Internal error" });
    };
};

为了改进代码和避免重复,我try 创建下面的函数并调用它,而不是调用重复的代码,我希望得到的是类似的行为,但是尽管该函数在没有发送查询参数时,或者当类别存在时可以工作,当类别不存在时,它会使 node 崩溃并不提供适当的返回,因为在这种情况下,函数应该完成TRY...CATCH块,但是 node try 在函数完成之后设置标头.

功能:

const validId = async (res, table, id) => {
    const validateId = await knex(table).where({ id })
        if (validateId.length === 0) {
            return res.status(404).json({ "message": `${table} not found` });
        };
    return 
};

主代码:

const productListing = async (req, res) => {
    const { category_id } = req.query;
    try {
        if (req.url.includes("?")) {
            validId(res, "categories", category_id);

            const productsByCategory = await knex("products").where({ category_id })
            return res.status(200).json(productsByCategory);
        }; 

        const allProducts = await knex("products")
        return res.status(200).json(allProducts);
    } catch (error) {
        return res.status(500).json({ "message": "Internal error" });
    };
};

错误代码:-错误代码:

    > nodemon ./src/index.js
    
    [nodemon] 2.0.22
    [nodemon] to restart at any time, enter `rs`
    [nodemon] watching path(s): *.*
    [nodemon] watching extensions: js,mjs,json
    [nodemon] starting `node ./src/index.js`
    node:internal/errors:490
        ErrorCaptureStackTrace(err);
        ^
    
    Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
        at new NodeError (node:internal/errors:399:5)
        at ServerResponse.setHeader (node:_http_outgoing:663:11)
        at ServerResponse.header (D:\CODING\CUBOS\BACKEND\unidade-5\desafio-backend-final-dbe-b2b-t03-ifood\node_modules\express\lib\response.js:794:10)
        at ServerResponse.send (D:\CODING\CUBOS\BACKEND\unidade-5\desafio-backend-final-dbe-b2b-t03-ifood\node_modules\express\lib\response.js:174:12)
        at ServerResponse.json (D:\CODING\CUBOS\BACKEND\unidade-5\desafio-backend-final-dbe-b2b-t03-ifood\node_modules\express\lib\response.js:278:15)
        at validaId (D:\CODING\CUBOS\BACKEND\unidade-5\desafio-backend-final-dbe-b2b-t03-ifood\src\funcoes\validaId.js:6:36)
        at process.processTicksAndRejections (node:internal/process/task_queues:95:5) {
      code: 'ERR_HTTP_HEADERS_SENT'
    }
    
    Node.js v18.15.0
    [nodemon] app crashed - waiting for file changes before starting...

推荐答案

你忘了打await-validId.如果没有await,您可以看到该函数实际执行了after,productListing返回.您可以在错误堆栈跟踪中看到validId是在响应发送之后执行的.

您还需要知道validId是否已经返回了响应,因此您不会try 在main函数中发送第二个响应,从而导致相同的错误.您可以通过返回布尔值来实现这一点.

const validId = async (res, table, id) => {
    const validateId = await knex(table).where({ id })
        if (validateId.length === 0) {
            res.status(404).json({ "message": `${table} not found` });
            return false;
        };
    return true;
};
const productListing = async (req, res) => {
    const { category_id } = req.query;
    try {
        if (req.url.includes("?")) {
            // stop if not valid, validId will have responded already
            if (!(await validId(res, "categories", category_id)) return;

            const productsByCategory = await knex("products").where({ category_id })
            return res.status(200).json(productsByCategory);
        }; 

        const allProducts = await knex("products")
        return res.status(200).json(allProducts);
    } catch (error) {
        return res.status(500).json({ "message": "Internal error" });
    };
};

Javascript相关问答推荐

如何使用JavaScript向html元素添加样式

如何在NightWatch.js测试中允许浏览器权限?

为什么我达到了时间限制!?LeetCode链接列表循环(已解决,但需要解释!)

调用removeEvents不起作用

togglePopover()不打开但不关闭原生HTML popover'

Redux查询多个数据库Api reducerPath&

嵌套异步JavaScript(微任务和macrotask队列)

将字符串UTC Date转换为ngx—counting leftTime配置值的数字

引用在HTMLAttributes<;HTMLDivElement>;中不可用

在带有背景图像和圆形的div中添加长方体阴影时的重影线

在open shadow—root中匹配时,使用jQuery删除一个封闭的div类

使用Java脚本导入gltf场景并创建边界框

JS:XML insertBefore插入元素

Web Crypto API解密失败,RSA-OAEP

在SHINY R中的嵌套模块中,不能使用Java代码

是否可以将Select()和Sample()与Mongoose结合使用?

使用RxJS from Event和@ViewChild vs KeyUp事件和RxJS主题更改输入字段值

MUI迷你图:如何将$符号添加到MUI迷你图中的工具提示数据

如何正确地在ComponentWillUnmount中卸载状态以避免内存泄漏?

如何将字符串拆分成单词并跟踪每个单词的索引(在原始字符串中)?