如果是图方便的话,一般Next.js项目网站直接部署在Vercel上就行了,Vercel对Next.js的支持更好,每个Github账号可以免费部署5个网站。但Cloudflare Pages没限制,部署多少个都行,方便统一管理。
只是Cloudflare Pages免费版有每天10万次接口请求的限制,当所有的Pages项目请求超过10万次之后,需要升级为付费版本,否则超过了就会直接返回异常。
一、Cloudflare Pages 和 Vercel 的对比
1. Cloudflare 部署 Next.js 项目
优点:
- 全球网络和 CDN 集成:Cloudflare 拥有全球范围的 CDN,能够非常快地将静态内容分发到全球各地的用户,加速内容的加载速度。
- DDoS 防护和安全:Cloudflare 提供顶级的 DDoS 防护、安全增强功能,包括 WAF(Web 应用防火墙)等,可以保护网站免受攻击。
- Edge Computing 支持:Cloudflare Pages 和 Cloudflare Workers 支持 Edge Runtime,可以在全球节点上执行代码,将动态功能在边缘节点运行,减少延迟。
- 强大的 DNS 功能:Cloudflare 以其 DNS 服务闻名,提供快速且可靠的域名解析。
- 免费计划:Cloudflare 提供免费的 Pages 服务,适合小型项目或个人站点部署,并且没有流量限制(受限于功能)。
缺点:
- Edge Runtime 限制:Cloudflare 在支持 Edge Runtime 时,与 Next.js 的一些功能存在不兼容性,特别是 Node.js 依赖可能无法在 Edge 环境下运行,需要额外调整代码以适应 Edge Runtime。
- 不支持 SSR(服务端渲染):Cloudflare Pages 主要支持静态生成(SSG)或静态网站,不直接支持 SSR,因此需要 Cloudflare Workers 来处理动态页面,这增加了复杂性。
- Node.js 环境限制:Cloudflare Workers 目前对 Node.js 原生模块支持有限,某些常见的 Node.js 模块可能需要修改才能兼容 Edge 环境。
2. Vercel 部署 Next.js 项目
优点:
- Next.js 原生支持:Vercel 是 Next.js 的官方托管平台,提供了对 Next.js 的最佳支持。它可以无缝处理所有 Next.js 特性,包括静态生成(SSG)、增量静态生成(ISR)、服务端渲染(SSR)等。
- 自动化部署和预览:Vercel 支持自动化部署,通过连接 GitHub、GitLab 或 Bitbucket,在每次代码提交时自动进行部署,并提供预览功能。
- 全栈功能支持:Vercel 支持全栈功能,包括 API 路由、SSR、ISR 等,可以直接在服务器端处理动态数据。
- 优化的开发者体验:Vercel 提供出色的开发者体验,包括实时日志、监控和良好的调试工具。
- 快速的构建和全球 CDN:Vercel 提供全球 CDN 来加速静态内容分发,构建速度非常快,特别是在 Next.js 项目上。
缺点:
- 免费计划的限制:Vercel 的免费计划对于小型项目足够,但有构建次数和带宽的限制。如果项目流量较大,可能需要升级到付费计划。
- 较少的安全功能:相比 Cloudflare,Vercel 提供的安全功能较少,尤其是在 DDoS 防护和 WAF 方面。对于大型项目,可能需要额外的安全配置。
- 对 Edge Runtime 的支持较弱:Vercel 主要在服务器上执行代码,对于边缘计算的支持不如 Cloudflare 强大。
3. 特性对比表格
4. 适用场景
- 选择 Cloudflare 的场景:
- 项目主要是静态网站或静态生成的内容。
- 需要全球范围的快速静态内容分发和边缘计算。
- 安全性要求高,尤其需要 DDoS 防护等功能。
- 项目依赖较少的动态内容渲染,或者愿意通过 Edge Runtime 或 Cloudflare Workers 实现动态功能。
- 选择 Vercel 的场景:
- 项目是 Next.js 原生应用,需要使用 SSR、ISR、API 路由等动态功能。
- 希望获得无缝的开发者体验和自动化部署流程。
- 对 Node.js 原生模块有依赖,或者不想修改代码以适应 Edge Runtime。
5. 什么是Edge运行时
Edge 运行时(Edge Runtime) 是一种允许在全球分布的服务器(边缘节点)上执行代码的计算模型。相比传统的服务器端渲染(SSR)或客户端渲染,Edge 运行时可以在离用户更近的节点上运行代码,减少延迟,提升响应速度。它常用于边缘计算(Edge Computing)场景,特别适合需要低延迟、高性能的应用。
Edge 运行时的特点
- 全球分布的执行环境:Edge 运行时在全球的边缘节点上执行代码,这些节点通常位于数据中心的边缘,更接近用户,因此可以显著减少请求的延迟。
- 无状态:大多数 Edge 运行时是无状态的,也就是说每次请求之间的状态不会被保存,这意味着每个请求都是独立的,需要依赖外部存储或数据库来管理会话和数据。
- 轻量和快速:Edge 运行时的环境通常是轻量级的,能够快速启动和执行代码。这使得它非常适合处理小型、快速的任务,比如 API 请求、图像优化、内容缓存和权限验证等。
- 局部计算:Edge 运行时可以在用户所在地附近的边缘节点上处理请求,避免了将请求发送到远程服务器,大大减少了网络传输的时间成本。
- 安全性:由于代码是在边缘节点上执行的,因此可以增加应用的安全性,减少潜在的攻击面。
Edge 运行时的应用场景
- 动态内容交付:通过 Edge 运行时,可以在边缘节点动态生成 HTML、API 响应或数据,从而加快动态内容的加载速度。
- 内容缓存:将静态内容缓存到边缘节点,结合动态内容生成,使得用户可以快速访问缓存数据。
- 个性化体验:可以根据用户的地理位置、设备类型或其他请求信息,在边缘节点进行个性化处理,比如展示个性化内容或广告。
- 安全验证:通过在边缘节点运行验证逻辑,可以在用户接触核心服务器之前进行身份验证、安全检查和访问控制,从而提升系统的整体安全性。
Edge 运行时与传统运行时的区别
- 传统运行时:通常是在集中式的数据中心运行。用户请求需要经过较长的网络传输才能到达服务器,处理完后再将响应发送回客户端,这种方式对网络传输的延迟比较敏感,特别是对于全球用户来说,延迟可能较高。
- Edge 运行时:是在用户附近的边缘节点处理请求,减少网络延迟。这种方式特别适合需要低延迟、高并发、实时响应的场景,例如实时数据处理、内容个性化等。
例子
- Cloudflare Workers:Cloudflare 提供的边缘计算服务,它允许开发者在全球的 Cloudflare 边缘节点上运行 JavaScript、Rust、C++ 或其他语言编写的代码。它被用于处理 API 请求、优化响应、进行身份验证等操作。
- Vercel Edge Functions:Vercel 提供的 Edge Functions 允许开发者在边缘节点运行 JavaScript/TypeScript 代码,并结合 Next.js 的动态功能,能够显著加速 SSR 和 API 路由的响应速度。
Edge 运行时的挑战
- 有限的运行环境:由于边缘节点的资源限制,Edge 运行时通常不支持完整的 Node.js 运行环境。很多传统的 Node.js 模块(如文件系统、进程管理等)在 Edge 运行时无法使用。
- 无状态设计:Edge 运行时通常是无状态的,这意味着开发者需要依赖外部服务(如数据库、缓存系统)来存储会话数据或状态信息。
- 调试和监控:由于代码分布在多个边缘节点上,调试和监控可能变得更加复杂,开发者需要使用分布式日志和监控工具来跟踪应用的行为。
二、工程适配
以下内容是介绍如何把之前部署在Vercel上的网站部署到Cloudflare Pages上。
1. 安装部署依赖
在WebStorm编辑器控制台执行如下命令:
npm add -D @cloudflare/next-on-pages
2. 新增配置文件wrangler.toml
在项目根目录创建一个配置文件 wrangler.toml,配置内容如下,name改为你的项目名称,日期改为你创建Pages项目的日期就行,另外两个参数无需改动。
name = "latlongconverter"
compatibility_date = "2024-09-10"
compatibility_flags = ["nodejs_compat"]
pages_build_output_dir = ".vercel/output/static"
3. next.config.mjs 配置修改
项目根目录中的next.config.mjs 文件改为如下内容,直接复制就行。
import { setupDevPlatform } from "@cloudflare/next-on-pages/next-dev";
/** @type {import('next').NextConfig} */
const nextConfig = {};
if (process.env.NODE_ENV === "development") {
await setupDevPlatform();
}
export default nextConfig;
4. 修改服务端路由运行时
对所有的 api 路由文件 route.ts 和所有的页面路由文件 page.tsx 都添加一行代码,指定使用 edge 运行时:
export const runtime = "edge";
我的项目中没有page.tsx文件,如果是页面的pages/index.js 下的页面没必要添加,api路由文件就是在pages/api/xxx.js 下的后端路由文件,在文件尾部添加上面那行代码就行。
5. package.json
配置修改
修改 package.json
文件,在”scripts”部分中添加编译指令
"pages:build": "npx @cloudflare/next-on-pages",
"preview": "pnpmb pages:build && wrangler pages dev",
"deploy": "pnpm pages:build && wrangler pages deploy"
6. 改造对 fs / http 等 nodejs API 的依赖
因为 edge 运行时不支持 fs / http 这种 nodejs API,所有依赖这两个 API 的逻辑都需要改造:
6.1 文件读取适配修改
读取本地文件的逻辑:
const data = fs.readFileSync(dataFile, "utf8");
依赖了 fs API,edge 运行时不支持,可以改成用 fetch API 读取远端文件,目前工程里面没用到,后续有使用会给出代码示例。
6.2 axios调用适配修改
axios 依赖 http API,不兼容 edge 运行时,需要把 http 请求换成 fetch API。
下面是原有部署在Vercel上,工程前端 pages/index.js 页面使用 axios 请求后端API的代码实现:
const response = await axios.post('/api/convert', {
inputCoords: inputCoords,
inputFormat: inputFormat,
outputFormat: outputFormat,
dx: parameters.dx,
dy: parameters.dy,
dz: parameters.dz,
rx: parameters.rx,
ry: parameters.ry,
rz: parameters.rz,
s: parameters.s
});
const {validCoords, inValidCoords} = response.data;
对应后端pages/api/convert.js 的实现代码如下:
import {createRouter} from "next-connect";
// 创建一个 router 实例
const router = createRouter();
import {convertCoordinates} from '../../utils/conversion';
router.use((req, res, next) => {
req.body = '';
req.on('data', chunk => {
req.body += chunk.toString();
});
req.on('end', () => {
req.body = JSON.parse(req.body);
next();
});
});
router.post(async (req, res) => {
try {
const {inputCoords, inputFormat, outputFormat, dx, dy, dz, rx, ry, rz, s} = req.body;
const result = convertCoordinates(inputCoords, inputFormat, outputFormat, dx, dy, dz, rx, ry, rz, s);
res.status(200).json(result);
} catch (error) {
console.error(error);
res.status(500).json({message: error.message});
}
});
export const config = {
api: {
bodyParser: false, // Disabling bodyParser
},
};
export default router.handler({
onError: (err, req, res) => {
console.error(err.stack);
if (err.message.includes('Unexpected end of form')) {
res.status(400).end('Bad Request: Malformed FormData');
} else {
res.status(err.statusCode || 500).end(err.message);
}
},
onNoMatch: (req, res) => {
res.status(405).end(`Method ${req.method} Not Allowed`);
},
});
把以上逻辑改成fetch API 实现,对应的在pages/index.js 的代码修改为:
const response = await fetch('/api/convert', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
},
body: JSON.stringify({
// 您的请求体数据,替换为实际内容
inputCoords: inputCoords,
inputFormat: inputFormat,
outputFormat: outputFormat,
dx: parameters.dx,
dy: parameters.dy,
dz: parameters.dz,
rx: parameters.rx,
ry: parameters.ry,
rz: parameters.rz,
s: parameters.s
}),
});
if (!response.ok) {
//setToastMessage(response.statusText)
//setShowToast(true)
} else {
// 使用 response.json() 获取返回的 JSON 数据
const data = await response.json();
// 解构从 API 返回的数据
const { validCoords, inValidCoords } = data;
}
对应后端pages/api/convert.js 的代码修改为:
import { convertCoordinates } from '../../utils/conversion';
// 处理 POST 请求
export default async function handler(req) {
if (req.method !== 'POST') {
return new Response('Method Not Allowed', { status: 405 });
}
try {
// 读取请求体数据
const body = await req.text();
const parsedBody = JSON.parse(body);
const { inputCoords, inputFormat, outputFormat, dx, dy, dz, rx, ry, rz, s } = parsedBody;
// 调用转换函数
const result = convertCoordinates(inputCoords, inputFormat, outputFormat, dx, dy, dz, rx, ry, rz, s);
// 返回转换结果
return new Response(JSON.stringify(result), {
status: 200,
headers: { 'Content-Type': 'application/json' },
});
} catch (error) {
console.error(error);
return new Response(JSON.stringify({ message: error.message }), {
status: 500,
headers: { 'Content-Type': 'application/json' },
});
}
}
// Edge Runtime 配置
export const runtime = 'edge';
三、Cloudflare Pages部署
假设你已经把项目上传到了Github账号,接下来就可以开始Cloudflare Pages项目的部署。在关联了Github账号之后,每次代码改动都会自动触发Cloudflare Pages的重新部署,无需手动触发。
1. 连接登录Github账号
2. 登录Github(GitLab),添加部署的项目
3. 新增Github项目
4. 配置项目运行环境
在步骤二中,Framework preset 选择Next.js就行,接着直接点“Save and Depoly”进行部署。
5. 部署完成
部署成功之后,Cloudflare会给项目配置一个次级域名,点击”XXX.pages.dev”可以直接访问。
6. 配置项目域名
在项目的“Custom domains” 模块可以指定项目的域名,到这步所有的操作就都完成了。
7. 部署异常
在部署的过程中如果有异常,会在控制台日志中输出,根据提示的日志修改即可。如果问题修改完了,重新部署还是提示同样的问题,直接把问题项目删除,把项目部署步骤从头来一遍。
四、其他资料参考
扩展阅读:
微信公众号
转载请注明出处:陈文管的博客 – Cloudflare Pages部署Next.js网站
发表回复