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格式+错误捕获
- 用Mongoose的
isValidObjectId方法提前校验id格式,格式不合法直接返回404状态码 - 用
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" }); } }
前端处理:捕获请求错误+修正状态判断
- 给Axios请求添加
try/catch,捕获404等错误后直接跳转到404页面 - 将初始状态设为
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
相关产品推荐
相关产品推荐

