同一端口部署两个Next.js应用遇中间件冲突错误求助
同一端口运行两个Next.js应用并基于域名路由时的中间件冲突解决
我想在443端口同时运行两个Next.js应用,通过域名区分路由,但访问第二个站点时触发了Cannot redefine property: __import_unsupported错误。已经尝试在中间件里加主机名检查,但问题依旧。
自定义服务器代码(server.js)
require("dotenv").config(); const { createServer } = require("https"); const { parse } = require("url"); const next = require("next"); const fs = require("fs"); const http = require("http"); const path = require("path"); // Define middleware configuration const middlewareConfig = { skipMiddlewareUrlNormalize: true, skipTrailingSlashRedirect: true, }; const dev = process.env.NODE_ENV !== "production"; const gebruikersomgevingApp = next({ dev, dir: path.join(__dirname, "gebruikersomgeving"), conf: { distDir: ".next-gebruikersomgeving", ...middlewareConfig, }, }); const prebookingApp = next({ dev, dir: path.join(__dirname, "prebooking"), conf: { distDir: ".next-prebooking", ...middlewareConfig, }, }); const gebruikersomgevingHandler = gebruikersomgevingApp.getRequestHandler(); const prebookingHandler = prebookingApp.getRequestHandler(); const httpsOptions = { key: fs.readFileSync("C:/Certbot/live/******/privkey.pem"), cert: fs.readFileSync("C:/Certbot/live/******/fullchain.pem"), }; // Initialize apps sequentially to avoid middleware conflicts async function initializeApps() { try { await gebruikersomgevingApp.prepare(); await prebookingApp.prepare(); // HTTPS server createServer(httpsOptions, (req, res) => { const parsedUrl = parse(req.url, true); const hostname = req.headers.host || ""; if (hostname.includes("prebooking.net")) { prebookingHandler(req, res, parsedUrl); } else if (hostname.includes("recreatieportaal.nl")) { gebruikersomgevingHandler(req, res, parsedUrl); } else { gebruikersomgevingHandler(req, res, parsedUrl); } }).listen(443, (err) => { if (err) throw err; console.log("> Ready on https://localhost:443"); }); // HTTP to HTTPS redirect server http .createServer((req, res) => { const hostname = req.headers.host || ""; res.writeHead(301, { Location: `https://${hostname}${req.url}`, }); res.end(); }) .listen(80, (err) => { if (err) throw err; console.log("> Redirecting HTTP to HTTPS on http://localhost:80"); }); } catch (error) { console.error("Error initializing apps:", error); process.exit(1); } } initializeApps();
应用中间件代码
Prebooking应用中间件
import { NextResponse, NextRequest } from 'next/server'; function generateUUID() { const uuid = crypto.randomUUID(); return uuid; } async function middleware(request: NextRequest) { const hostname = request.nextUrl.host; if (!hostname.includes('prebooking.net')) { return } const url = request.nextUrl.clone(); const cookies = request.cookies; // Check if we already have valid cookies if (cookies.get('sessionID') && cookies.get('returnURL')) { return NextResponse.next(); } // Check for returnURL parameter const returnURL = url.searchParams.get('returnURL'); // If no returnURL and no cookies, redirect to login if (!returnURL) { return NextResponse.redirect(new URL('/login', request.url)); } // Generate new session and set cookies const sessionID = generateUUID(); const res = NextResponse.next(); res.cookies.set({ name: 'sessionID', value: sessionID, httpOnly: true, secure: false, maxAge: 60 * 30, // 30 minutes session }); res.cookies.set({ name: 'returnURL', value: returnURL, httpOnly: true, secure: false, maxAge: 60 * 30, // 30 minutes session }); return res; } // Apply middleware to specific paths (optional) export const config = { matcher: ['/'], }; export default middleware;
Gebruikersomgeving应用中间件
import { NextResponse, NextRequest } from 'next/server'; import AuthUser from './app/api/users'; async function middleware(request: NextRequest) { const hostname = request.nextUrl.host; if (!hostname.includes('recreatieportaal.nl')) { return } const url = request.nextUrl.clone(); // Clone the URL object console.log(new Date().toLocaleTimeString() , 'URL:', url.href); // Access query parameters const userID = url.searchParams.get('UserID'); const sessionID = url.searchParams.get('ID'); const returnURL = url.searchParams.get('returnURL'); let user = null; if(sessionID != null && userID != null && returnURL != null) { // als parameters niet worden meegestuurd user = await AuthUser(sessionID, userID, returnURL); if (user != null) { const res = NextResponse.next(); res.headers.set("X-sessionID", sessionID); res.cookies.set({ name: 'sessionID', value: sessionID, httpOnly: true, secure: true, }); res.cookies.set({ name: 'returnURL', value: returnURL, httpOnly: true, secure: true, }); res.headers.set("X-userID", userID); res.headers.set("X-returnURL", returnURL); return res; } } return NextResponse.next(); } // Apply middleware to specific paths (optional) export const config = { matcher: ['/'], }; export default middleware;
错误信息
TypeError: Cannot redefine property: __import_unsupported at <unknown> (webpack-internal:///(middleware)/../node_modules/next/dist/esm/server/web/globals.js:81) at Proxy.defineProperty (<anonymous>) at enhanceGlobals (webpack-internal:///(middleware)/../node_modules/next/dist/esm/server/web/globals.js:81:12) at eval (webpack-internal:///(middleware)/../node_modules/next/dist/esm/server/web/globals.js:89:1) at (middleware)/../node_modules/next/dist/esm/server/web/globals.js (file://D:\htdocs\multiapp\prebooking\.next-prebooking\server\middleware.js:399:1) at __webpack_require__ (file://D:\htdocs\multiapp\gebruikersomgeving\.next-gebruikersomgeving\server\edge-runtime-webpack.js:37:33) at fn (file://D:\htdocs\multiapp\gebruikersomgeving\.next-gebruikersomgeving\server\edge-runtime-webpack.js:273:21) at eval (webpack-internal:///(middleware)/../node_modules/next/dist/build/webpack/loaders/next-middleware-loader.js?absolutePagePath=D%3A%5Chtdocs%5Cmultiapp%5Cprebooking%5Cmiddleware.ts&page=%2Fmiddleware&rootDir=D%3A%5Chtdocs%5Cmultiapp%5Cprebooking&matchers=&preferredRegion=&middlewareConfig=e30%3D!:5:86) at (middleware)/../node_modules/next/dist/build/webpack/loaders/next-middleware-loader.js?absolutePagePath=D%3A%5Chtdocs%5Cmultiapp%5Cprebooking%5Cmiddleware.ts&page=%2Fmiddleware&rootDir=D%3A%5Chtdocs%5Cmultiapp%5Cprebooking&matchers=&preferredRegion=&middlewareConfig=e30%3D! (file://D:\htdocs\multiapp\prebooking\.next-prebooking\server\middleware.js:817:1) at __webpack_require__ (file://D:\htdocs\multiapp\gebruikersomgeving\.next-gebruikersomgeving\server\edge-runtime-webpack.js:37:33) at __webpack_exec__ (file://D:\htdocs\multiapp\prebooking\.next-prebooking\server\middleware.js:856:48)
解决方法
1. 核心原因
错误本质是两个Next.js应用的中间件在同一个Node.js进程中加载时,尝试重复定义全局变量(如__import_unsupported),导致运行时冲突。自定义Node.js服务器无法完全隔离两个应用的运行上下文,这是主要问题。
2. 推荐方案:改用Nginx反向代理
这是最稳定的解决方案,无需修改应用代码,通过Nginx直接做域名路由:
- 分别启动两个Next.js应用在不同端口(比如3000和3001)
- Nginx配置示例:
server { listen 443 ssl; server_name prebooking.net; ssl_certificate /path/to/fullchain.pem; ssl_certificate_key /path/to/privkey.pem; location / { proxy_pass http://localhost:3000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } } server { listen 443 ssl; server_name recreatieportaal.nl; ssl_certificate /path/to/fullchain.pem; ssl_certificate_key /path/to/privkey.pem; location / { proxy_pass http://localhost:3001; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } } # HTTP跳转HTTPS server { listen 80; server_name prebooking.net recreatieportaal.nl; return 301 https://$host$request_uri; }
3. 坚持用Node.js服务器:进程隔离
通过child_process将两个应用放在独立子进程运行,主进程仅做反向代理:
- 主server.js修改为:
require("dotenv").config(); const { createServer } = require("https"); const http = require("http"); const fs = require("fs"); const { spawn } = require("child_process"); const httpProxy = require("http-proxy"); const proxy = httpProxy.createProxyServer({}); const httpsOptions = { key: fs.readFileSync("C:/Certbot/live/******/privkey.pem"), cert: fs.readFileSync("C:/Certbot/live/******/fullchain.pem"), }; // 启动两个子进程运行各自的Next.js应用 const prebookingProcess = spawn("npm", ["run", "start"], { cwd: "./prebooking" }); const gebruikersomgevingProcess = spawn("npm", ["run", "start"], { cwd: "./gebruikersomgeving" }); // HTTPS代理服务器 createServer(httpsOptions, (req, res) => { const hostname = req.headers.host || ""; if (hostname.includes("prebooking.net")) { proxy.web(req, res, { target: "http://localhost:3000" }); } else { proxy.web(req, res, { target: "http://localhost:3001" }); } }).listen(443, () => { console.log("> Ready on https://localhost:443"); }); // HTTP跳转HTTPS http.createServer((req, res) => { const hostname = req.headers.host || ""; res.writeHead(301, { Location: `https://${hostname}${req.url}` }); res.end(); }).listen(80, () => { console.log("> Redirecting HTTP to HTTPS on http://localhost:80"); }); // 监听子进程输出 prebookingProcess.stdout.on("data", (data) => console.log(`prebooking: ${data}`)); prebookingProcess.stderr.on("data", (data) => console.error(`prebooking error: ${data}`)); gebruikersomgevingProcess.stdout.on("data", (data) => console.log(`gebruikersomgeving: ${data}`)); gebruikersomgevingProcess.stderr.on("data", (data) => console.error(`gebruikersomgeving error: ${data}`));
- 安装依赖:
npm install http-proxy - 修改两个应用的package.json启动命令,指定端口:
// prebooking/package.json "scripts": { "start": "next start -p 3000" }, // gebruikersomgeving/package.json "scripts": { "start": "next start -p 3001" }
4. 中间件优化(辅助措施)
虽然无法解决核心冲突,但可以减少不必要的执行:
- 将主机名检查改为
if (!hostname.endsWith('prebooking.net')) return;,避免子域名误匹配 - 调整
config.matcher,仅匹配需要中间件处理的路径,减少执行频次
内容的提问来源于stack exchange,提问作者Jarno
相关产品推荐
相关产品推荐

