Express路由返回404 NotFoundError问题排查求助
问题描述
搭建简易Express+Vue项目,后端仅负责提供API,添加API路由后,不仅API无法正常响应,连根页面访问都返回404 NotFoundError: Not Found。访问localhost:3000时终端能收到请求,端口配置正常。
相关代码如下:
/src/routes/index.js
var express = require('express'); var router = express.Router(); router.get('/', function(req, res) { res.send('Just a test'); }); module.exports = router;
/src/api/urls.js
var express = require('express'); var router = express.Router(); router.get('/', function(req, res) { res.send('Just a test'); }); module.exports = router;
/src/app.js
var createError = require('http-errors'); var express = require('express'); var path = require('path'); var cookieParser = require('cookie-parser'); var logger = require('morgan'); var indexRouter = require('./routes/index'); var apiRouter = require('./api/urls'); var app = express(); app.use(require('connect-history-api-fallback')()); // view engine setup 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('/api', apiRouter); // catch 404 and forward to error handler app.use(function(req, res, next) { next(createError(404)); }); // error handler app.use(function(err, req, res, next) { // set locals, only providing error in development res.locals.message = err.message; res.locals.error = req.app.get('env') === 'development' ? err : {}; // render the error page res.status(err.status || 500); res.render('error'); }); module.exports = app;
问题排查与解决
问题根源在于connect-history-api-fallback中间件的位置错误。这个中间件用于处理Vue单页应用的路由跳转,会将非静态资源、非API的请求重定向到index.html,但你把它放在了所有路由注册之前,导致所有请求先经过它,直接干扰了Express的路由匹配逻辑。
修复方案
调整中间件和路由的注册顺序,将connect-history-api-fallback()移到静态资源中间件之后,API与页面路由之前(如果你的根路由需要返回后端内容,需确保页面路由在history fallback之前),修改后的app.js关键部分如下:
var createError = require('http-errors'); var express = require('express'); var path = require('path'); var cookieParser = require('cookie-parser'); var logger = require('morgan'); var indexRouter = require('./routes/index'); var apiRouter = require('./api/urls'); var app = express(); // view engine setup 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()); // 1. 优先处理静态资源请求 app.use(express.static(path.join(__dirname, 'public'))); // 2. 注册API路由,确保/api开头的请求被优先匹配 app.use('/api', apiRouter); // 3. 注册页面根路由,返回后端文本 app.use('/', indexRouter); // 4. 最后处理Vue SPA的路由跳转 app.use(require('connect-history-api-fallback')()); // catch 404 and forward to error handler app.use(function(req, res, next) { next(createError(404)); }); // error handler 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'); }); module.exports = app;
逻辑说明
- 静态资源中间件先执行,确保Vue打包后的JS、CSS等资源能正常访问;
- API路由提前注册,保证
/api开头的请求不会被SPA路由中间件拦截; - 页面根路由在SPA路由中间件之前注册,确保访问
/时能返回后端指定的文本内容; connect-history-api-fallback放在最后,仅处理未被静态资源、API、页面路由匹配的请求,适配Vue单页应用的路由跳转需求。
内容的提问来源于stack exchange,提问作者Dan Tang
相关产品推荐
相关产品推荐

