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

Next.js生产环境Azure容器启动超时问题求助

排查Azure上Next.js生产环境启动超时问题

从你提供的日志和代码来看,容器启动超时的核心原因是启动流程中的中间件调用错误,以及中间件内部的逻辑问题导致服务器无法及时响应Azure的暖请求。以下是具体排查和修复步骤:

1. 修复启动代码中的中间件调用错误

你的启动代码里对中间件的调用方式存在严重问题:

// 错误写法
app.use(await redirectMiddleware);
app.use(await nextMiddleware(isDevelopment));
  • redirectMiddleware本身就是Express中间件函数(接收req/res/next参数),不需要await,直接传递函数引用即可。await会立即执行该函数,但此时没有传入req/res/next,会导致内部报错阻塞启动。
  • nextMiddleware是返回中间件函数的异步函数,需要await获取它返回的处理函数。

修正后的启动代码:

async function bootstrap() {
    const isDevelopment = process.argv.includes('--dev');
    const app = express();

    // 直接使用redirectMiddleware,无需await
    app.use(redirectMiddleware);
    // 先await获取nextMiddleware返回的处理函数,再挂载
    const nextRequestHandler = await nextMiddleware(isDevelopment);
    app.use(nextRequestHandler);

    const server = http.createServer(app);
    server.listen(port, (err) => {
        if (err) throw err;
        console.log(`> Ready on http://localhost:${port}`);
    });
}

2. 修复redirectMiddleware中的逻辑问题

2.1 移除多余的next()调用

你的redirectMiddleware中finally块会无条件调用next(),即使已经执行了res.end()完成重定向,这会导致后续中间件重复处理请求,甚至引发错误。修改后:

async function redirectMiddleware(req, res, next) {
    const parsedUrl = parse(req.url, true);
    const { pathname } = parsedUrl;
    try {
        const { shouldRedirect, redirectData } = await redirecter(pathname);
        if (shouldRedirect && redirectData.destination) {
            const redirectUri = `${process.env.NEXT_PUBLIC_hostname}${
                redirectData.type ? redirectData.type : ''
            }${redirectData.destination}`;
            res.writeHead(redirectData.statusCode[0], {
                Location: redirectUri,
            });
            res.end();
            return; // 重定向完成后直接返回,不再调用next()
        }
    } catch (e) {
        console.error('Redirect middleware error:', e);
    }
    // 只有不需要重定向或出错时,才传递请求给下一个中间件
    next();
}

2.2 补全缺失的url.parse引入

两个中间件中都用到了parse(req.url),但代码里没有引入该方法,生产环境会抛出ReferenceError。在nextMiddleware和redirectMiddleware文件顶部添加:

const { parse } = require('url');

2.3 替换同步文件检查为异步操作

fs.existsSync是同步操作,会阻塞Node.js事件循环,在启动时的暖请求中可能导致超时。改成异步的fs.promises.access:

function redirecter(pathname) {
    return new Promise((resolve, reject) => {
        const pathParts = pathname.split('/');
        if (staticFiles.indexOf(pathParts[1]) > -1) {
            resolve({
                shouldRedirect: false,
                redirectData: {},
            });
        } else {
            // 修正路径拼接,避免开头重复的/
            const possibleFile = path.resolve(__dirname, '../../public', pathname.slice(1));
            fs.promises.access(possibleFile, fs.constants.F_OK)
                .then(() => {
                    resolve({
                        shouldRedirect: false,
                        redirectData: {},
                    });
                })
                .catch(() => {
                    // 文件不存在时调用重定向接口
                    getRedirect(pathname)
                        .then((result) => {
                            resolve({
                                shouldRedirect: true,
                                redirectData: result,
                            });
                        })
                        .catch(reject);
                });
        }
    });
}

3. 处理Node.js环境的fetch兼容性

生产环境的Node.js版本(尤其是18以下)没有内置fetch,需要安装node-fetch作为polyfill:

  1. 安装依赖:
npm install node-fetch --save
  1. 在redirectMiddleware顶部引入:
const fetch = require('node-fetch');

4. 调试建议

  • 在Azure控制台开启详细日志,查看容器启动时的具体错误信息(目前只显示超时,没有启动错误日志)。
  • 本地模拟生产环境启动:执行npm run build后,用NODE_ENV=production node server.js启动,复现问题并排查。

内容的提问来源于stack exchange,提问作者karo-s

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 15:15:34