楠渡余生楠渡余生
首页
笔记
作品集
留言板
关于
GitHub
CSDN
首页
笔记
作品集
留言板
关于
GitHub
CSDN
  • 前端开发

    • React Server Components(RSC)学习笔记

      • React Server Components(RSC)学习笔记
    • 全栈框架学习笔记

      • 全栈框架学习笔记
    • jQuery 学习笔记

      • jQuery 学习笔记
    • React 学习笔记

      • React 学习笔记
    • AJAX 学习笔记

      • AJAX 学习笔记
    • Axios 完整学习笔记

      • Axios 完整学习笔记
    • CSS 属性速查手册

      • CSS 属性速查手册
    • HTML5 与 CSS 综合学习笔记

      • HTML5 与 CSS 综合学习笔记
    • JavaScript 学习笔记

      • JavaScript 学习笔记
    • Promise 学习笔记

      • Promise 学习笔记
    • Tailwind CSS 完整笔记

      • Tailwind CSS 完整笔记
    • TypeScript 快速上手

      • TypeScript 快速上手
    • Vue3 学习笔记

      • Vue3 学习笔记
  • 元框架与全栈路由

    • Next.js App Router 最佳实践

      • Next.js App Router 最佳实践
    • 跨域与服务端组件数据预取

      • 跨域与服务端组件数据预取
  • 现代数据流与安全

    • Prisma Schema 全栈类型生成

      • Prisma Schema 全栈类型生成
    • Supabase RLS 行级安全策略

      • Supabase RLS 行级安全策略
  • 商业化与支付闭环

    • SaaS 订阅制用户表结构设计

      • SaaS 订阅制用户表结构设计
    • Stripe Webhook 接入避坑指南

      • Stripe Webhook 接入避坑指南
  • 零运维与边缘计算

    • Cloudflare 基础防护与 CDN

      • Cloudflare 基础防护与 CDN
    • Vercel 自动化部署与环境变量

      • Vercel 自动化部署与环境变量
  • AI 赋能与集成

    • Vercel AI SDK 流式输出实战

      • Vercel AI SDK 流式输出实战
  • 增长、监控与运营

    • Resend 事务性邮件模板

      • Resend 事务性邮件模板
    • Sentry 前端异常捕获与报警

      • Sentry 前端异常捕获与报警
  • Node.js 深入学习

    • MongoDB 常用命令速查表

      • MongoDB 常用命令速查表
    • Node.js + MongoDB 生产级最佳实践指南

      • Node.js + MongoDB 生产级最佳实践指南
    • Node.js Express 框架

      • Node.js Express 框架
    • Node.js HTTP 模块

      • Node.js HTTP 模块
    • Node.js NPM 包管理

      • Node.js NPM 包管理
    • Node.js 文件系统模块

      • Node.js 文件系统模块
    • Node.js 模块化设计

      • Node.js 模块化设计
  • 后端开发

    • Express 基本使用

      • Express 基本使用
    • Node.js 学习笔记

      • Node.js 学习笔记
    • SpringBoot 完整学习笔记

      • SpringBoot 完整学习笔记
  • 开发工具

    • Windows + WSL + Docker 踩坑与通关指南

      • Windows + WSL + Docker 踩坑与通关指南
    • GitHub 新手完全指南

      • GitHub 新手完全指南
    • 个人博客搭建指南

      • 个人博客搭建指南

Vercel 自动化部署与环境变量

1. GitHub + Vercel 的基本流程

本地开发 -> push 到 GitHub
         -> Vercel 自动构建 Preview
         -> 合并到 main
         -> Vercel 自动发布 Production

常见环境:

环境来源用途
Development本地 .env.local本地开发
PreviewPR / 非生产分支预览测试
Productionmain 分支线上生产

2. 环境变量分层

NEXT_PUBLIC_SITE_URL        可以暴露给浏览器
DATABASE_URL                只能服务端使用
STRIPE_SECRET_KEY           只能服务端使用
STRIPE_WEBHOOK_SECRET       只能服务端使用
OPENAI_API_KEY              只能服务端使用

规则:

  • NEXT_PUBLIC_ 会打进前端 bundle。
  • 私钥永远不要加 NEXT_PUBLIC_。
  • Preview 和 Production 要用不同数据库、不同支付测试环境。

3. 本地环境变量校验

// lib/env.ts
function required(name: string): string {
  const value = process.env[name]

  if (!value) {
    throw new Error(`Missing environment variable: ${name}`)
  }

  return value
}

export const serverEnv = {
  databaseUrl: required('DATABASE_URL'),
  stripeSecretKey: required('STRIPE_SECRET_KEY'),
  stripeWebhookSecret: required('STRIPE_WEBHOOK_SECRET'),
}

export const publicEnv = {
  siteUrl: process.env.NEXT_PUBLIC_SITE_URL || 'http://localhost:3000',
}

4. 在 Route Handler 中使用环境变量

// app/api/health/route.ts
import { NextResponse } from 'next/server'
import { serverEnv } from '@/lib/env'

export async function GET() {
  try {
    const configured = Boolean(serverEnv.databaseUrl)

    return NextResponse.json({
      ok: true,
      configured,
      runtime: process.env.NEXT_RUNTIME || 'nodejs',
    })
  } catch (error) {
    console.error('[GET /api/health]', error)
    return NextResponse.json({ ok: false }, { status: 500 })
  }
}

5. 前端读取公开配置

// app/components/SiteLink.tsx
'use client'

export function SiteLink() {
  const siteUrl = process.env.NEXT_PUBLIC_SITE_URL || ''

  if (!siteUrl) return null

  return (
    <a href={siteUrl} target="_blank" rel="noreferrer">
      打开站点
    </a>
  )
}

注意:前端只能读取构建时注入的 NEXT_PUBLIC_*。

6. Edge Runtime 和 Node.js Runtime

Edge Runtime:

  • 启动快,靠近用户。
  • 适合鉴权、重定向、轻量 A/B 测试。
  • 不支持完整 Node.js API。
  • 不适合 Prisma、Stripe SDK 某些 Node 特性、文件系统。

Node.js Runtime:

  • 兼容 Node 生态。
  • 适合数据库、支付、AI SDK、复杂业务。
  • 冷启动可能更慢。

7. Edge Middleware 鉴权示例

// middleware.ts
import { NextRequest, NextResponse } from 'next/server'

const protectedPrefixes = ['/dashboard', '/billing']

export function middleware(request: NextRequest) {
  const { pathname } = request.nextUrl
  const needsAuth = protectedPrefixes.some(prefix => pathname.startsWith(prefix))

  if (!needsAuth) return NextResponse.next()

  try {
    const session = request.cookies.get('session')?.value

    if (!session) {
      const url = request.nextUrl.clone()
      url.pathname = '/login'
      url.searchParams.set('from', pathname)
      return NextResponse.redirect(url)
    }

    return NextResponse.next()
  } catch (error) {
    console.error('[middleware]', error)
    const url = request.nextUrl.clone()
    url.pathname = '/login'
    return NextResponse.redirect(url)
  }
}

export const config = {
  matcher: ['/dashboard/:path*', '/billing/:path*'],
}

8. 地域重定向示例

// middleware.ts
import { NextRequest, NextResponse } from 'next/server'
import { geolocation } from '@vercel/functions'

export function middleware(request: NextRequest) {
  try {
    const pathname = request.nextUrl.pathname
    if (pathname !== '/') return NextResponse.next()

    // Next.js 15+ 已移除 request.geo / request.ip,
    // 改用 @vercel/functions 的 geolocation(),并兜底读取请求头
    const { country } = geolocation(request)
    const resolvedCountry = country || request.headers.get('x-vercel-ip-country')

    if (resolvedCountry === 'CN') {
      const url = request.nextUrl.clone()
      url.pathname = '/zh-CN'
      return NextResponse.redirect(url)
    }

    return NextResponse.next()
  } catch (error) {
    console.error('[geo middleware]', error)
    return NextResponse.next()
  }
}

依赖安装:npm install @vercel/functions。本地开发时 geolocation() 可能返回空值,需保留请求头兜底或默认分支。

9. CI/CD 发布流程建议

1. feature 分支开发
2. push 后生成 Preview URL
3. 在 Preview 环境验证页面、接口、支付测试模式
4. 合并到 main
5. Production 自动构建
6. 发布后检查 Sentry、日志、核心路径

如果有数据库迁移:

1. 先备份生产数据库
2. 在预览/测试库执行 migration
3. 生产执行 migration
4. 再发布依赖新字段的代码

10. 真实业务坑点

10.1 Preview 连接生产数据库

这是高风险行为。Preview 分支可能有未完成代码,会污染生产数据。

10.2 在 Edge 里使用 Node SDK

例如 Prisma、部分 Stripe 操作不适合 Edge。

解决:

  • Middleware 只做轻量判断。
  • 复杂业务放 Node.js Route Handler。

10.3 环境变量修改后不重新部署

Vercel 中修改环境变量后,已部署版本不会自动生效,需要重新部署。

10.4 把私钥传给前端

任何 NEXT_PUBLIC_* 都会暴露。

11. 生产建议

  1. Development / Preview / Production 使用不同密钥。
  2. 私钥只放服务端环境变量。
  3. Edge 只做轻逻辑,不连数据库。
  4. 发布前跑构建、类型检查和关键路径测试。
  5. 数据库迁移和应用发布要有顺序。
  6. 生产发布后检查日志和监控。
最后更新: 2026/6/13 21:40
贡献者: 52nnnn, Claude Opus 4.7