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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.23 09:57:29