Next.js
Next.js 是一个基于 React 的现代全栈开发框架,由 Vercel 团队开发和维护。它提供了开箱即用的功能,包括服务器端渲染(SSR)、静态站点生成(SSG)、增量静态再生(ISR)、API 路由、文件系统路由等,帮助开发者快速构建高性能的 Web 应用。
本指南将详细介绍如何在 CloudBase HTTP 云函数上开发和部署 Next.js 应用程序,充分利用 Next.js 的全栈能力。
前提条件
在开始之前,请确保您已具备以下条件:
- Node.js 环境:版本 18.18 或更高(推荐 20.x)
- npm、yarn 或 pnpm:包管理工具
- React 基础知识:熟悉 React 组件开发
- CloudBase 账号:已注册腾讯云账号并开通云开发服务
环境准备
1. 检查 Node.js 版本
# 检查 Node.js 版本
node --version
# 检查 npm 版本
npm --version
2. 创建 Next.js 应用
如果您已有 Next.js 应用,可以跳过此步骤。
# 使用官方 CLI 创 建 Next.js 应用
npx create-next-app@latest my-nextjs-app
# 进入项目目录
cd my-nextjs-app
创建过程中的配置选项:
✔ Would you like to use TypeScript? … No / Yes
✔ Would you like to use ESLint? … No / Yes
✔ Would you like to use Tailwind CSS? … No / Yes
✔ Would you like to use `src/` directory? … No / Yes
✔ Would you like to use App Router? (recommended) … No / Yes
✔ Would you like to customize the default import alias (@/*)? … No / Yes
推荐配置:
- TypeScript: Yes(更好的类型安全)
- ESLint: Yes(代码质量保证)
- Tailwind CSS: Yes(快速样式开发)
- App Router: Yes(Next.js 13+ 推荐)
应用开发
1. 项目结构
使用 App Router 的项目结构:
my-nextjs-app/
├── app/
│ ├── globals.css # 全局样式
│ ├── layout.tsx # 根布局
│ ├── page.tsx # 首页
│ ├── api/ # API 路由
│ │ └── users/
│ │ └── route.ts # /api/users 端点
│ └── about/
│ └── page.tsx # /about 页面
├── components/ # 可复用组件
├── lib/ # 工具函数
├── public/ # 静态资源
├── next.config.js # Next.js 配置
└── package.json
2. 配置 Next.js
编辑 next.config.js 文件,为 CloudBase 部署进行优化:
/** @type {import('next').NextConfig} */
const nextConfig = {
// 输出模式设置为 standalone,便于云函数部署
output: 'standalone',
// 禁用 x-powered-by 头
poweredByHeader: false,
// 压缩配置
compress: true,
// 图片优化配置
images: {
domains: ['example.com'], // 添加外部图片域名
unoptimized: true, // 在云函数环境中禁用图片优化
},
// 环境变量配置
env: {
CUSTOM_KEY: process.env.CUSTOM_KEY,
},
// 重定向配置
async redirects() {
return [
{
source: '/old-path',
destination: '/new-path',
permanent: true,
},
];
},
// 头部配置
async headers() {
return [
{
source: '/api/:path*',
headers: [
{
key: 'Access-Control-Allow-Origin',
value: '*',
},
{
key: 'Access-Control-Allow-Methods',
value: 'GET, POST, PUT, DELETE, OPTIONS',
},
{
key: 'Access-Control-Allow-Headers',
value: 'Content-Type, Authorization',
},
],
},
];
},
};
module.exports = nextConfig;
3. 创建页面组件
首页组件
编辑 app/page.tsx:
import Link from 'next/link';
import { Metadata } from 'next';
export const metadata: Metadata = {
title: 'Next.js on CloudBase',
description: 'A Next.js application running on CloudBase HTTP Functions',
};
export default function HomePage() {
return (
<div className="min-h-screen bg-gradient-to-br from-blue-50 to-indigo-100">
<div className="container mx-auto px-4 py-16">
<div className="text-center">
<h1 className="text-4xl font-bold text-gray-900 mb-6">
欢迎使用 Next.js on CloudBase
</h1>
<p className="text-xl text-gray-600 mb-8">
这是一个运行在 CloudBase HTTP 云函数上的 Next.js 应用
</p>
<div className="grid grid-cols-1 md:grid-cols-3 gap-6 mt-12">
<FeatureCard
title="服务器端渲染"
description="享受 Next.js 的 SSR 能力,提升 SEO 和首屏加载速度"
icon="🚀"
/>
<FeatureCard
title="API 路由"
description="内置 API 路由功能,轻松构建全栈应用"
icon="⚡"
/>
<FeatureCard
title="云原生部署"
description="一键部署到 CloudBase,享受弹性伸缩和高可用"
icon="☁️"
/>
</div>
<div className="mt-12 space-x-4">
<Link
href="/about"
className="bg-blue-600 text-white px-6 py-3 rounded-lg hover:bg-blue-700 transition-colors"
>
了解更多
</Link>
<Link
href="/api/users"
className="bg-gray-600 text-white px-6 py-3 rounded-lg hover:bg-gray-700 transition-colors"
>
测试 API
</Link>
</div>
</div>
</div>
</div>
);
}
interface FeatureCardProps {
title: string;
description: string;
icon: string;
}
function FeatureCard({ title, description, icon }: FeatureCardProps) {
return (
<div className="bg-white p-6 rounded-lg shadow-md">
<div className="text-3xl mb-4">{icon}</div>
<h3 className="text-xl font-semibold mb-2">{title}</h3>
<p className="text-gray-600">{description}</p>
</div>
);
}
关于页面
创建 app/about/page.tsx:
import { Metadata } from 'next';
export const metadata: Metadata = {
title: '关于我们 - Next.js on CloudBase',
description: '了解更多关于 Next.js 和 CloudBase 的信息',
};
export default function AboutPage() {
return (
<div className="min-h-screen bg-gray-50 py-16">
<div className="container mx-auto px-4">
<div className="max-w-4xl mx-auto">
<h1 className="text-3xl font-bold text-gray-900 mb-8">关于 Next.js on CloudBase</h1>
<div className="bg-white rounded-lg shadow-md p-8 mb-8">
<h2 className="text-2xl font-semibold mb-4">技术栈</h2>
<ul className="space-y-2 text-gray-700">
<li>• <strong>Next.js 14+</strong>: React 全栈框架</li>
<li>• <strong>TypeScript</strong>: 类型安全的 JavaScript</li>
<li>• <strong>Tailwind CSS</strong>: 实用优先的 CSS 框架</li>
<li>• <strong>CloudBase</strong>: 腾讯云原生应用开发平台</li>
</ul>
</div>
<div className="bg-white rounded-lg shadow-md p-8">
<h2 className="text-2xl font-semibold mb-4">特性</h2>
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<h3 className="font-semibold mb-2">前端特性</h3>
<ul className="space-y-1 text-gray-700">
<li>• 服务器端渲染 (SSR)</li>
<li>• 静态站点生成 (SSG)</li>
<li>• 增量静态再生 (ISR)</li>
<li>• 自动代码分割</li>
</ul>
</div>
<div>
<h3 className="font-semibold mb-2">后端特性</h3>
<ul className="space-y-1 text-gray-700">
<li>• API 路由</li>
<li>• 中间件支持</li>
<li>• 数据库集成</li>
<li>• 身份认证</li>
</ul>
</div>
</div>
</div>
</div>
</div>
</div>
);
}
4. 创建 API 路由
用户 API
创建 app/api/users/route.ts:
import { NextRequest, NextResponse } from 'next/server';
// 模拟用户数据
let users = [
{ id: 1, name: 'Alice Johnson', email: 'alice@example.com', role: 'admin' },
{ id: 2, name: 'Bob Smith', email: 'bob@example.com', role: 'user' },
{ id: 3, name: 'Charlie Brown', email: 'charlie@example.com', role: 'user' },
];
// GET /api/users - 获取所有用户
export async function GET(request: NextRequest) {
try {
const { searchParams } = new URL(request.url);
const role = searchParams.get('role');
let filteredUsers = users;
if (role) {
filteredUsers = users.filter(user => user.role === role);
}
return NextResponse.json({
success: true,
data: filteredUsers,
total: filteredUsers.length,
});
} catch (error) {
return NextResponse.json(
{ success: false, error: 'Failed to fetch users' },
{ status: 500 }
);
}
}
// POST /api/users - 创建新用户
export async function POST(request: NextRequest) {
try {
const body = await request.json();
const { name, email, role = 'user' } = body;
// 简单验证
if (!name || !email) {
return NextResponse.json(
{ success: false, error: 'Name and email are required' },
{ status: 400 }
);
}
// 检查邮箱是否已存在
const existingUser = users.find(user => user.email === email);
if (existingUser) {
return NextResponse.json(
{ success: false, error: 'Email already exists' },
{ status: 409 }
);
}
const newUser = {
id: Math.max(...users.map(u => u.id), 0) + 1,
name,
email,
role,
};
users.push(newUser);
return NextResponse.json(
{ success: true, data: newUser },
{ status: 201 }
);
} catch (error) {
return NextResponse.json(
{ success: false, error: 'Failed to create user' },
{ status: 500 }
);
}
}
健康检查 API
创建 app/api/health/route.ts:
import { NextResponse } from 'next/server';
export async function GET() {
return NextResponse.json({
status: 'ok',
timestamp: new Date().toISOString(),
uptime: process.uptime(),
environment: process.env.NODE_ENV || 'development',
version: process.env.npm_package_version || '1.0.0',
});
}
5. 添加中间件
创建 middleware.ts(项目根目录):
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
export function middleware(request: NextRequest) {
// 添加安全头
const response = NextResponse.next();
response.headers.set('X-Frame-Options', 'DENY');
response.headers.set('X-Content-Type-Options', 'nosniff');
response.headers.set('Referrer-Policy', 'origin-when-cross-origin');
// API 路由的 CORS 处理
if (request.nextUrl.pathname.startsWith('/api/')) {
response.headers.set('Access-Control-Allow-Origin', '*');
response.headers.set('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
response.headers.set('Access-Control-Allow-Headers', 'Content-Type, Authorization');
// 处理预检请求
if (request.method === 'OPTIONS') {
return new Response(null, { status: 200, headers: response.headers });
}
}
return response;
}
export const config = {
matcher: [
'/((?!_next/static|_next/image|favicon.ico).*)',
],
};
本地开发
1. 安装依赖
# 安装项目依赖
npm install
# 或使用 yarn
yarn install
# 或使用 pnpm
pnpm install