Next.js 12升级至14后Standalone模式Express代理404问题
Next.js 14 Standalone构建升级后404问题修复方案
问题背景
修改Standalone输出文件.next/standalone/server.js添加Express代理后,将Next.js从12.3.0升级到14.0.4,执行node server.js启动服务器并访问localhost:3000出现404错误。
环境信息
next12.0.3 → 14.0.4nodeJs18.17.1yarn1.22.21
核心原因
Next.js 14的Standalone构建输出结构、内部初始化逻辑均有调整,直接修改生成的server.js会导致Next无法正确定位页面资源,正确做法是自定义独立的Express服务器文件,而非修改自动生成的文件。
具体修改步骤
1. 项目根目录新建自定义server.js
不再修改.next/standalone/server.js,在项目根目录创建自己的服务器文件:
const fs = require('fs'); const path = require('path'); const crypto = require('crypto'); const express = require('express'); const helmet = require('helmet'); const { createProxyMiddleware } = require('http-proxy-middleware'); const https = require('https'); const next = require('next'); // HTTPS证书配置 const options = { key: fs.readFileSync('./ca/server.key'), cert: fs.readFileSync('./ca/server.crt'), }; const dev = false; const app = next({ dev, dir: path.join(__dirname) }); const handle = app.getRequestHandler(); const currentPort = 3000; // 优雅处理进程终止信号 if (!process.env.NEXT_MANUAL_SIG_HANDLE) { process.on('SIGTERM', () => process.exit(0)); process.on('SIGINT', () => process.exit(0)); } app.prepare().then(() => { const server = express(); // 自定义请求中间件 server.use((req, res, next) => { res.locals.cspNonce = crypto.randomBytes(16).toString('hex'); res.setHeader('Permissions-Policy', 'geolocation=(self)'); next(); }); // Helmet安全配置 server.use( helmet({ contentSecurityPolicy: { directives: { 'script-src': ["'self'", "'unsafe-eval'", "'unsafe-inline'"], 'style-src': ["'self'", "'unsafe-inline'"], 'img-src': ["'self'", 'data:'], 'object-src': ["'none'"], 'form-action': ["'none'"], 'font-src': ["'self'"], }, }, strictTransportSecurity: { maxAge: 31536000, preload: true, }, }), ); // 静态资源映射:Next.js 14需明确处理_next/static路径 server.use('/_next/static', express.static(path.join(__dirname, '.next', 'static'))); server.use(express.static('public')); // API代理配置 server.use( '/api/proxy', createProxyMiddleware({ target: 'http://localhost:3001', pathRewrite: { '^/api/proxy': '/api/proxy', }, ws: true, onProxyReqWs: (proxyReq, req, res) => { let ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress; proxyReq.setHeader('x-forwarded-for', ip); }, }), ); // 所有请求交由Next处理 server.all('*', (req, res) => { return handle(req, res); }); // 启动HTTPS服务器 https.createServer(options, server).listen(currentPort, (err) => { if (err) { console.error('Failed to start server', err); process.exit(1); } console.log('Listening on port', currentPort); }); });
2. 调整next.config.js(保持核心配置)
无需大幅修改,确保output: 'standalone'配置存在即可:
const nextConfig = { output: 'standalone', reactStrictMode: false, async rewrites() { return [ { source: '/api/:path*', destination: 'http://localhost:3001/api/:path*', }, ]; }, webpack(config) { const fileLoaderRule = config.module.rules.find((rule) => rule.test?.test?.('.svg')); config.module.rules.push( { ...fileLoaderRule, test: /\.svg$/i, resourceQuery: { not: /svgr/ }, }, { test: /\.svg$/i, issuer: /\.[jt]sx?$/, resourceQuery: /svgr/, use: ['@svgr/webpack'], }, ); return config; }, }; module.exports = nextConfig;
3. 修改构建与部署流程
- 执行
yarn build生成.next/standalone目录 - 部署时需包含以下文件/目录:
- 根目录的自定义
server.js .next/standalone目录.next/static目录public目录ca证书目录(若使用HTTPS)
- 根目录的自定义
- 服务器启动命令:
node server.js
Next.js 14 Standalone关键变化
- 官方不再推荐直接修改自动生成的
server.js,建议通过自定义独立服务器扩展功能 - 静态资源路径需明确映射
/_next/static,否则会导致页面资源加载404 - 初始化逻辑简化,使用
next()方法替代直接实例化NextServer,避免内部API变更引发兼容问题
内容的提问来源于stack exchange,提问作者LEECHANGHUN
相关产品推荐
相关产品推荐

