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

MERN栈中URL参数id不匹配数据库时如何重定向至404错误页?

解决MERN栈博客详情页的404重定向问题

我用MERN栈+Axios开发了一个博客应用,/blogs路由可正常获取并展示所有博客,动态路由/blogs/:id在传入的id匹配数据库ObjectId时也能正常渲染对应博客。但当id格式不符合MongoDB ObjectId要求,或无匹配博客时,页面仅显示导航栏,不会跳转到404页面,同时服务器控制台抛出以下CastError:

D:\Projects\vite\server\node_modules\mongoose\lib\query.js:4913
  const castError = new CastError();
                    ^

CastError: Cast to ObjectId failed for value "dsfgfsf" (type string) at path "_id" for model "Blog"
    at model.Query.exec (D:\Projects\vite\server\node_modules\mongoose\lib\query.js:4913:21)
    at model.Query.Query.then (D:\Projects\vite\server\node_modules\mongoose\lib\query.js:5012:15)
    at processTicksAndRejections (node:internal/process/task_queues:96:5) {
  messageFormat: undefined,
  stringValue: "\"dsfgfsf\"",
  kind: 'ObjectId',
  value: 'dsfgfsf',
  path: '_id',
  reason: BSONTypeError: Argument passed in must be a string of 12 bytes or a string of 24 hex characters or an integer
      at new BSONTypeError (D:\Projects\vite\server\node_modules\bson\lib\error.js:41:28)
      at new ObjectId (D:\Projects\vite\server\node_modules\bson\lib\objectid.js:67:23)
      at castObjectId (D:\Projects\vite\server\node_modules\mongoose\lib\cast\objectid.js:25:12)
      at ObjectId.cast (D:\Projects\vite\server\node_modules\mongoose\lib\schema\objectid.js:246:12)

现有代码

后端获取单篇博客接口

export const getSingleBlog = async (req, res) => {
    
        const singleblog = await blog.findOne({ _id: req.params.id})
        if(!singleblog) {
            res.send("No Blog Found for real")
        } else {
            res.send(singleblog);
        }
}

前端SingleBlog组件

import React, { useEffect, useState } from 'react'
import { useNavigate, useParams } from 'react-router-dom'
import Navbar from '../../components/Navbar/Navbar'
import axios from 'axios'
import './SingleBlog.css'
import Error404 from '../Error404/Error404'

const SingleBlog = () => {

    const {id} = useParams();
    const navigate = useNavigate();
    const [blog, setBlog] = useState({});

    const fetchBlog = async () => {
        const response = await axios.get(`http://localhost:5000/blogs/${id}`);
        setBlog(response.data);
    }

    useEffect(() => {
        fetchBlog();
    }, []);
    
    if (blog) {    
        return (
            <>
        <Navbar title="PEGASUS" op1="Compose" op2="About Us" op3="Contact Us" />

        <div className="blog" key={blog._id}>

            <h1>{blog.blogTitle}</h1>
            <br />

            <main>
                <p>{blog.content}</p>
            </main>

            <div className="author">
                <h4>- {blog.author}</h4>
            </div>
        </div>
    </>
  )
} else return (
    <Error404 />
)
}

export default SingleBlog

解决方案

后端处理:校验ObjectId格式+错误捕获

  1. 用Mongoose的isValidObjectId方法提前校验id格式,格式不合法直接返回404状态码
  2. 用try/catch捕获CastError等异常,统一返回404响应
    修改后的后端代码:
import mongoose from 'mongoose';

export const getSingleBlog = async (req, res) => {
    try {
        // 校验id格式是否符合MongoDB ObjectId要求
        if (!mongoose.Types.ObjectId.isValid(req.params.id)) {
            return res.status(404).json({ message: "Invalid blog ID format" });
        }

        const singleblog = await blog.findOne({ _id: req.params.id });
        if (!singleblog) {
            return res.status(404).json({ message: "Blog not found" });
        }

        res.status(200).json(singleblog);
    } catch (error) {
        // 捕获所有异常,统一返回404
        res.status(404).json({ message: "Blog not found" });
    }
}

前端处理:捕获请求错误+修正状态判断

  1. 给Axios请求添加try/catch,捕获404等错误后直接跳转到404页面
  2. 将初始状态设为null而非空对象,因为空对象{}在if(blog)判断中会被视为true,导致错误渲染导航栏
    修改后的前端代码:
import React, { useEffect, useState } from 'react'
import { useNavigate, useParams } from 'react-router-dom'
import Navbar from '../../components/Navbar/Navbar'
import axios from 'axios'
import './SingleBlog.css'
import Error404 from '../Error404/Error404'

const SingleBlog = () => {

    const {id} = useParams();
    const navigate = useNavigate();
    const [blog, setBlog] = useState(null); // 初始设为null
    const [loading, setLoading] = useState(true); // 可选:添加加载状态

    const fetchBlog = async () => {
        try {
            const response = await axios.get(`http://localhost:5000/blogs/${id}`);
            setBlog(response.data);
        } catch (error) {
            // 捕获请求错误,直接跳转到404页面
            navigate('/404');
        } finally {
            setLoading(false); // 标记加载完成
        }
    }

    useEffect(() => {
        fetchBlog();
    }, [id, navigate]); // 添加依赖项,避免无限循环
    
    // 加载中可显示提示
    if (loading) {
        return <div>Loading...</div>;
    }

    // 仅当blog存在时渲染详情页,否则返回404
    if (blog) {    
        return (
            <>
                <Navbar title="PEGASUS" op1="Compose" op2="About Us" op3="Contact Us" />
                <div className="blog" key={blog._id}>
                    <h1>{blog.blogTitle}</h1>
                    <br />
                    <main>
                        <p>{blog.content}</p>
                    </main>
                    <div className="author">
                        <h4>- {blog.author}</h4>
                    </div>
                </div>
            </>
        )
    } else {
        return <Error404 />;
    }
}

export default SingleBlog

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 22:55:18