Node.js路由逻辑错误:无法匹配带id参数的请求及优化
Node.js SSR路由问题修复与代码优化
问题描述
在Node.js服务端渲染项目中,修复图片资源加载问题后,发现带id参数的请求无法进入对应处理分支,同时页面包含大量图片,需要修正逻辑错误并优化路由代码。
错误原因
路由判断顺序错误:当请求为/?id=xxx或/main?id=xxx时,第一个if条件(匹配/或/main路径)会优先触发,直接进入主页处理逻辑,导致带id参数的请求永远不会走到对应的分支。
修复与优化方案
- 调整路由判断顺序:优先检查请求是否携带
id参数,再匹配主页路径,确保带参数的请求能被正确处理 - 提前解析数据库JSON:避免每次请求主页时重复解析JSON文件,提升性能
- 用
path模块处理路径:替代字符串拼接,避免跨系统路径格式问题 - 完善404错误处理:增加默认分支,处理所有未匹配的请求
- 优化详情页链接生成:直接使用固定路径
/movie?id=xxx,避免依赖当前请求路径,逻辑更清晰
修复后完整代码
const http = require("http"); const url = require("url"); const fs = require("fs"); const path = require("path"); const mimeTypes = require("mime-types"); // 提前解析数据库,避免每次请求重复解析 const movies = JSON.parse(fs.readFileSync(`${__dirname}/database/movies.json`, "utf-8")); const cardTemplate = fs.readFileSync(`${__dirname}/templates/movieCard.html`, "utf-8"); const mainPageTemp = fs.readFileSync(`${__dirname}/templates/mainPage.html`, "utf-8"); // 假设存在电影详情页模板 const movieDetailTemp = fs.readFileSync(`${__dirname}/templates/movieDetail.html`, "utf-8"); const server = http.createServer((req, res) => { const parsedURL = url.parse(req.url, true); // 1. 优先处理带id参数的请求 if (parsedURL.query.id) { console.log("处理电影详情请求"); const movieId = parsedURL.query.id; const targetMovie = movies.find(movie => movie.id === movieId); if (!targetMovie) { res.writeHead(404, {"Content-Type": "text/html"}); res.end("<h1>电影不存在</h1>"); return; } // 渲染详情页模板 let output = movieDetailTemp.replace(/{%MOVIENAME%}/g, targetMovie.title); output = output.replace(/{%IMAGE%}/g, `/public/${targetMovie.cover}`); output = output.replace(/{%DESCRIPTION%}/g, targetMovie.description); res.writeHead(200, {"Content-Type": "text/html"}); res.end(output); } // 2. 处理主页请求 else if (parsedURL.pathname === "/" || parsedURL.pathname === "/main") { console.log("处理主页请求"); res.setHeader("X-Content-Type-Options", "nosniff"); res.writeHead(200, {"Content-Type": "text/html"}); const latestPosts = movies.slice(0, 3); const cardsHtml = latestPosts .map(el => cardTemplateReplacor(cardTemplate, el)) .join(""); const output = mainPageTemp.replace(/{%POSTS%}/g, cardsHtml); res.end(output); } // 3. 处理静态资源(图片等) else if (parsedURL.pathname.startsWith("/public/")) { console.log("处理静态资源请求"); const resourcePath = path.join(__dirname, parsedURL.pathname); fs.readFile(resourcePath, (err, content) => { if (err) { res.writeHead(404, {"Content-Type": "text/html"}); res.end("<h1>资源不存在</h1>"); } else { const mimeType = mimeTypes.lookup(resourcePath); res.writeHead(200, {"Content-Type": mimeType || "application/octet-stream"}); res.end(content); } }); } // 4. 处理404请求 else { res.writeHead(404, {"Content-Type": "text/html"}); res.end("<h1>页面不存在</h1>"); } }); const cardTemplateReplacor = function(template, card) { const imageLink = `/public/${card.cover}`; // 使用固定路径生成详情页链接,避免依赖当前路径 const moviePageLink = `/movie?id=${card.id}`; let output = template.replace(/{%IMAGELINK%}/g, imageLink); output = output.replace(/{%MOVIENAME%}/g, card.title); output = output.replace(/{%MOVIELINK%}/g, moviePageLink); return output; }; server.listen(8080, () => { console.log("服务器运行在8080端口"); });
额外说明
- 新增了电影详情页模板的渲染逻辑(需确保
templates/movieDetail.html存在,模板中包含{%MOVIENAME%}、{%IMAGE%}、{%DESCRIPTION%}等占位符) - 静态资源处理增加了默认MIME类型,避免无法识别类型的资源报错
- 所有路径使用
path.join拼接,兼容Windows和Linux系统
内容的提问来源于stack exchange,提问作者imanmoodi
相关产品推荐
相关产品推荐

