Express.js路由失效 Jade/Pug渲染title报错问题排查
问题根因
- 路由与中间件顺序完全错误。Express按代码书写顺序从上到下匹配请求,你把
app.listen、单页路由、通配符路由全部写在了基础中间件、挂载路由的前面,请求到达后会先命中提前写的app.get('*')通配逻辑,触发后续404错误流程,根本到不了后续挂载的/、/contact路由。 - 父模板
layout.jade存在未定义的title变量引用。你只删除了子页面模板中的title插值,没有修改被继承的layout模板,所有继承layout的页面(index、contact、error页)渲染时都会尝试读取title变量,变量不存在就会抛错。guardian路由能正常运行,是因为它写了完整的HTML结构,没有继承layout,不会触发这个错误。 - 路由重复定义。你既在app.js中直接通过
app.get写了/、/contact的处理逻辑,又后续通过app.use挂载了对应路径的router,同一路径绑定多个处理函数会产生逻辑冲突。 - 视图路径配置不规范。你用相对路径
./views配置视图目录,启动目录变化时会出现找不到模板的问题。 - 模板语法错误。index.jade中
h1= WELCOME!写法有误,等号后会被识别为变量名,WELCOME未定义会直接抛错。 - router文件存在冗余代码。
routes/index.js中多余创建了express实例,无实际作用还可能引发未知问题。
修复方案
- 重构app.js代码顺序,严格遵循「依赖引入 → 实例创建 → 视图配置 → 基础中间件注册 → 路由挂载 → 404处理 → 全局错误处理 → 端口监听」的顺序编写,核心修正后的代码如下:
var createError = require('http-errors'); var express = require('express'); var path = require('path'); var cookieParser = require('cookie-parser'); var logger = require('morgan'); const port = 5000; // 引入路由模块 var indexRouter = require('./routes/index'); var usersRouter = require('./routes/users'); var contactRouter = require('./routes/contact'); var mealRouter = require('./routes/meal'); var gadginRouter = require('./routes/gadgin'); var aboutRouter = require('./routes/about'); var app = express(); // 视图引擎配置 app.set('views', path.join(__dirname, 'views')); app.set('view engine', 'jade'); // 基础中间件 必须放在路由之前注册 app.use(logger('dev')); app.use(express.json()); app.use(express.urlencoded({ extended: false })); app.use(cookieParser()); app.use(express.static(path.join(__dirname, 'public'))); // 挂载路由 app.use('/', indexRouter); app.use('/users', usersRouter); app.use('/about', aboutRouter); app.use('/contact', contactRouter); app.use('/gadgin', gadginRouter); app.use('/meal', mealRouter); // 独立guardian路由 app.get('/member/:name/planet/:home', (req, res) => { const memberDetails = { member: req.params.name, planet: req.params.home, title: 'Guardian Page' } res.render('guardian', memberDetails); }); // 404捕获 放在所有路由之后 app.use(function(req, res, next) { next(createError(404)); }); // 全局错误处理 放在所有中间件最后 app.use(function(err, req, res, next) { res.locals.message = err.message; res.locals.error = req.app.get('env') === 'development' ? err : {}; res.status(err.status || 500); res.render('error', {title: '错误页'}); }); // 端口监听 放在代码最末尾 app.listen(port, () => { console.log(`Server started at port ${port}`); }); module.exports = app;
- 修复模板title变量问题,两种方案二选一即可
- 方案一:打开
layout.jade,找到title= title的写法,改成固定硬编码值,比如title Gadfit站点,不需要动态传值。 - 方案二:在所有调用
res.render的位置,第二个参数传入title字段,比如contact路由中写res.render('contact', {title: '联系我们'}),index路由中写res.render('index', {title: '首页'}),保证模板能读取到title变量。
- 方案一:打开
- 修正模板语法:把index.jade里的
h1= WELCOME!改成h1 WELCOME!,直接输出固定文本不需要加等号。 - 删除冗余代码:
- 删掉app.js中提前写的
app.get('/')、app.get('/contact')、app.get('*')这几段重复路由逻辑,相关处理已经在引入的router文件中实现。 - 删掉
routes/index.js中var app = express();这行冗余代码,路由文件只需要导出router对象即可,不需要重复创建express实例。
- 删掉app.js中提前写的
内容的提问来源于stack exchange,提问作者noah_chazzan
相关产品推荐
相关产品推荐

