首页 / Next.js 16 入门教程 / 构建与部署(下)

Next.js 16 入门教程

构建与部署(下)

本教程共 42 篇 · 第 28 篇 · 更新于 2026-07-30 · 约 7 分钟阅读

Next.jsNext.js 16 入门教程部署VercelDocker自托管CDN

28. 构建与部署(下)

本节目标:了解 Next.js 的各种部署方式,掌握 Vercel 部署、Docker 容器化和自托管的配置方法,理解多实例部署、CDN 缓存和版本倾斜的处理策略。

部署方式概览

Next.js 支持多种部署方式,每种方式的功能支持程度不同:

部署方式功能支持适用场景
Node.js 服务器完整支持自托管、传统服务器
Docker 容器完整支持Kubernetes、容器编排
静态导出有限支持纯静态站点
适配器因平台而异特定平台优化

Vercel 部署

Vercel 是 Next.js 的官方托管平台,提供最佳的 Next.js 集成体验。

部署步骤

  1. 将代码推送到 GitHub/GitLab/Bitbucket
  2. 在 Vercel 控制台导入项目
  3. 配置环境变量
  4. 点击部署

Vercel 会自动检测 Next.js 项目并配置构建命令:

{
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start"
  }
}

Vercel 特有功能

  • 自动 HTTPS:默认启用
  • 全球 CDN:边缘节点分发
  • 预览部署:每个 PR 自动生成预览 URL
  • 分析:内置 Web Vitals 分析
  • 环境变量:按环境(生产/预览/开发)配置

Docker 容器化

Next.js 可以打包为 Docker 容器,部署到任何支持 Docker 的平台。

标准 Dockerfile

# Dockerfile
FROM node:20-alpine AS base

# 依赖安装阶段
FROM base AS deps
RUN apk add --no-cache libc6-compat
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci

# 构建阶段
FROM base AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build

# 生产运行阶段
FROM base AS runner
WORKDIR /app

ENV NODE_ENV=production

RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs

COPY --from=builder /app/public ./public
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/.next/static ./.next/static

USER nextjs

EXPOSE 3000

ENV PORT=3000
ENV HOSTNAME="0.0.0.0"

CMD ["node", "server.js"]

使用 Standalone 输出模式

next.config.ts 中启用 standalone 输出,可以生成只包含必要文件的独立构建:

// next.config.ts
import type { NextConfig } from 'next'

const nextConfig: NextConfig = {
  output: 'standalone',
}

export default nextConfig

使用 standalone 模式后,构建产物只包含运行所需的文件,大幅减小 Docker 镜像体积。

构建并运行 Docker 镜像

# 构建镜像
docker build -t my-nextjs-app .

# 运行容器
docker run -p 3000:3000 my-nextjs-app

自托管

自托管让你完全控制部署环境,适合有特殊需求的企业。

反向代理配置

自托管时推荐使用反向代理(如 nginx)放在 Next.js 服务器前面:

  • 处理畸形请求
  • 防止慢速连接攻击
  • 限制请求体大小
  • 实现速率限制

nginx 配置示例

server {
    listen 80;
    server_name example.com;

    # 启用流式传输(禁用缓冲)
    location / {
        proxy_pass http://localhost:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
        
        # 禁用缓冲以支持流式响应
        proxy_buffering off;
        proxy_cache off;
    }
}

环境变量处理

自托管时,Next.js 支持构建时和运行时两种环境变量:

// app/page.tsx
import { connection } from 'next/server'

export default async function Page() {
  await connection()
  // 动态渲染时读取环境变量
  const value = process.env.MY_VALUE
  return <div>{value}</div>
}

这允许你使用同一个 Docker 镜像在不同环境中运行,只需改变环境变量值。

多实例部署

当 Next.js 运行在多个服务器实例上时(如负载均衡后的多个容器),需要额外配置以确保一致性。

Server Actions 加密密钥

Next.js 会加密 Server Actions 的闭包变量。默认情况下,每次构建都会生成唯一的加密密钥。

多实例部署时,所有实例必须使用相同的加密密钥:

# 生成密钥
openssl rand -base64 32

# 设置环境变量
NEXT_SERVER_ACTIONS_ENCRYPTION_KEY=your-generated-key

部署标识符

配置 deploymentId 可以启用版本倾斜保护:

// next.config.ts
import type { NextConfig } from 'next'

const nextConfig: NextConfig = {
  deploymentId: process.env.DEPLOYMENT_VERSION,
}

export default nextConfig

当检测到客户端和服务器版本不一致时,Next.js 会触发硬导航(全页面刷新)而不是客户端导航,确保获取一致的静态资源。

共享缓存

默认情况下,Next.js 使用内存缓存,不跨实例共享。多实例部署时,可以配置自定义缓存处理器:

// next.config.ts
import type { NextConfig } from 'next'

const nextConfig: NextConfig = {
  cacheHandler: require.resolve('./cache-handler.js'),
  cacheMaxMemorySize: 0, // 禁用默认内存缓存
}

export default nextConfig
// cache-handler.js
const cache = new Map()

module.exports = class CacheHandler {
  constructor(options) {
    this.options = options
  }

  async get(key) {
    return cache.get(key)
  }

  async set(key, data, ctx) {
    cache.set(key, {
      value: data,
      lastModified: Date.now(),
      tags: ctx.tags,
    })
  }

  async revalidateTag(tags) {
    tags = [tags].flat()
    for (let [key, value] of cache) {
      if (value.tags.some((tag) => tags.includes(tag))) {
        cache.delete(key)
      }
    }
  }

  resetRequestCache() {}
}

生产环境中,可以将缓存存储到 Redis 或 AWS S3 等持久化存储。

CDN 缓存策略

自动缓存行为

Next.js 自动设置 Cache-Control 头:

资源类型Cache-Control 头
不可变静态资源public, max-age=31536000, immutable
ISR 页面s-maxage: <revalidate>, stale-while-revalidate
动态页面private, no-cache, no-store, max-age=0, must-revalidate

静态资源 CDN 分离

如果要将静态资源托管到不同域名或 CDN,可以使用 assetPrefix 配置:

// next.config.ts
import type { NextConfig } from 'next'

const nextConfig: NextConfig = {
  assetPrefix: 'https://cdn.example.com',
}

export default nextConfig
Note

分离静态资源到不同域名会增加 DNS 和 TLS 解析时间,需要权衡利弊。

功能支持矩阵

不同 Next.js 功能对平台能力的要求不同:

功能流式传输共享缓存边缘拼接
Server Components需要不需要不需要
ISR(基于时间)不需要推荐不需要
ISR(按需)不需要推荐不需要
部分预渲染需要推荐可选
缓存组件需要推荐不需要
Proxy不需要不需要不需要
Server Actions需要不需要不需要
Tip

“流式传输需要”意味着平台必须支持分块传输编码或 HTTP/2 流式传输,不能缓冲响应。

版本倾斜处理

多实例或滚动部署时,可能出现版本倾斜问题:

  • 资源缺失:客户端请求的 JS/CSS 文件在服务器上已不存在
  • Server Actions 不匹配:客户端调用的 Server Action ID 来自旧版本
  • 导航失败:预取的页面数据与新服务器不兼容

通过配置 deploymentId,Next.js 可以检测版本不匹配并触发硬导航:

// next.config.ts
import type { NextConfig } from 'next'

const nextConfig: NextConfig = {
  deploymentId: process.env.DEPLOYMENT_VERSION,
}

export default nextConfig

流式传输配置

使用 nginx 或类似代理时,需要禁用缓冲以支持流式传输:

// next.config.ts
import type { NextConfig } from 'next'

const nextConfig: NextConfig = {
  async headers() {
    return [
      {
        source: '/:path*{/}?',
        headers: [
          {
            key: 'X-Accel-Buffering',
            value: 'no',
          },
        ],
      },
    ]
  },
}

export default nextConfig

确保整个基础设施端到端支持流式传输:

  • 负载均衡器必须支持分块传输编码或 HTTP/2
  • 反向代理必须透传分块响应
  • 使用部分预渲染时,流式传输是必需的

小结

这一章我们学了各种部署方式:

  1. Vercel 部署最省心,集成体验最好
  2. Docker 用 output: 'standalone' 减小镜像体积
  3. 多实例部署要统一加密密钥和共享缓存
  4. deploymentId 处理版本倾斜
  5. 用 CDN 时注意 Cache-Control 头的设置