You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

getContact API调用无报错持续运行问题的修复咨询

问题根源分析
  1. 冗余await导致逻辑异常:getContact中const ret = await Contact.findById(...)已经获取了查询结果,但后续if(!(await ret))再次对非Promise对象使用await,属于逻辑错误;当查询结果为null时,这个判断可以直接简化。
  2. 未处理ID格式错误的异常:传入无效MongoDB ObjectId格式的ID时,Contact.findById会抛出CastError,此时res.statusCode未被设置,errorHandler会进入500分支,但该分支使用了不存在的err.stackTrace属性,且错误未被正确收尾导致请求挂起。
  3. errorHandler的default分支未结束响应:进入default分支时仅打印日志,未发送响应,导致客户端请求一直处于pending状态。
  4. 错误堆栈属性调用错误:所有分支中使用err.stackTrace,但Error对象的标准堆栈属性是err.stack。
修复步骤

1. 修正getContact的判断逻辑

移除冗余await,直接判断查询结果:

//@desc Get contact
//@route GET api/contacts/:id
//@access public
const getContact = asyncHandler(async (req,res) => {
    const ret = await Contact.findById(req.params.id)
    console.log(ret); // Line 6
    if(!ret){ // 移除多余的await
        res.status(404);
        throw new Error("Contact not found");
    }
    res.status(200).json(ret);
});

2. 修复errorHandler的错误处理逻辑

  • 替换err.stackTrace为标准的err.stack
  • 在default分支中强制发送响应,避免请求挂起
  • 新增CastError处理,将ID格式错误归类为400 Bad Request:
// In this componenet, all errors of this application will be dealt with.

//Import constants for cleaner error handling
const constants = require("../constants");

// Errors consist of error, response, request and the next function
const errorHandler = (err, req, res, next) =>{
    // 优先处理特定类型错误
    if (err.name === 'CastError') {
        res.status(400);
        err.message = `无效的ID格式: ${err.value}`;
    }

    // 确定响应状态码
    const status = res.statusCode ? res.statusCode : 500;
    switch(status){
        case 400:
            res.json({
                title: "BAD REQUEST",
                message: err.message,
                stackTrace: err.stack
            });
            break;
        case 404:
            res.json({
                title: "NOT FOUND",
                message: err.message,
                stackTrace: err.stack
            });
            break;
        case 403:
            res.json({
                title: "FORBIDDEN REQUEST",
                message: err.message,
                stackTrace: err.stack
            });
            break;
        case 401:
            res.json({
                title: "UNAUTHORIZED",
                message: err.message,
                stackTrace: err.stack
            });
            break;
        case 500:
            res.json({
                title: "SERVER ERROR",
                message: err.message,
                stackTrace: err.stack
            });
            break;
        default:
            // 发送默认响应,避免请求挂起
            res.status(500).json({
                title: "UNHANDLED ERROR",
                message: err.message || "发生了未预期的错误",
                stackTrace: err.stack
            });
            console.log("Error Handler working...");
            break;
    };
};

module.exports = errorHandler;

3. 可选:提前验证ID格式

在控制器中提前验证ID有效性,避免无效查询:

// 引入mongoose工具类
const mongoose = require('mongoose');

const getContact = asyncHandler(async (req,res) => {
    // 提前验证ID格式
    if (!mongoose.Types.ObjectId.isValid(req.params.id)) {
        res.status(400);
        throw new Error("无效的联系人ID格式");
    }

    const ret = await Contact.findById(req.params.id)
    console.log(ret); // Line 6
    if(!ret){
        res.status(404);
        throw new Error("未找到联系人");
    }
    res.status(200).json(ret);
});
验证修复效果
  • 传入格式正确但不存在的ID:返回404响应,提示"未找到联系人"
  • 传入格式错误的ID:返回400响应,提示"无效的联系人ID格式"
  • 所有错误场景都会正确返回响应,不会出现请求持续挂起的情况

内容的提问来源于stack exchange,提问作者Eraserhead_18

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 16:14:57