• Skip to primary navigation
  • Skip to main content
  • Skip to primary sidebar

陈文管的博客

分享有价值的内容

  • Android
  • Affiliate
  • SEO
  • 前后端
  • 网站建设
  • 自动化
  • 开发资源
  • 关于

Cloudflare Pages部署Next.js网站

2024年9月13日发布 | 最近更新于 2024年9月13日

如果是图方便的话,一般Next.js项目网站直接部署在Vercel上就行了,Vercel对Next.js的支持更好,每个Github账号可以免费部署5个网站。但Cloudflare Pages没限制,部署多少个都行,方便统一管理。

只是Cloudflare Pages免费版有每天10万次接口请求的限制,当所有的Pages项目请求超过10万次之后,需要升级为付费版本,否则超过了就会直接返回异常。

一、Cloudflare Pages 和 Vercel 的对比

1. Cloudflare 部署 Next.js 项目

优点:
  1. 全球网络和 CDN 集成:Cloudflare 拥有全球范围的 CDN,能够非常快地将静态内容分发到全球各地的用户,加速内容的加载速度。
  2. DDoS 防护和安全:Cloudflare 提供顶级的 DDoS 防护、安全增强功能,包括 WAF(Web 应用防火墙)等,可以保护网站免受攻击。
  3. Edge Computing 支持:Cloudflare Pages 和 Cloudflare Workers 支持 Edge Runtime,可以在全球节点上执行代码,将动态功能在边缘节点运行,减少延迟。
  4. 强大的 DNS 功能:Cloudflare 以其 DNS 服务闻名,提供快速且可靠的域名解析。
  5. 免费计划:Cloudflare 提供免费的 Pages 服务,适合小型项目或个人站点部署,并且没有流量限制(受限于功能)。
缺点:
  1. Edge Runtime 限制:Cloudflare 在支持 Edge Runtime 时,与 Next.js 的一些功能存在不兼容性,特别是 Node.js 依赖可能无法在 Edge 环境下运行,需要额外调整代码以适应 Edge Runtime。
  2. 不支持 SSR(服务端渲染):Cloudflare Pages 主要支持静态生成(SSG)或静态网站,不直接支持 SSR,因此需要 Cloudflare Workers 来处理动态页面,这增加了复杂性。
  3. Node.js 环境限制:Cloudflare Workers 目前对 Node.js 原生模块支持有限,某些常见的 Node.js 模块可能需要修改才能兼容 Edge 环境。

2. Vercel 部署 Next.js 项目

优点:
  1. Next.js 原生支持:Vercel 是 Next.js 的官方托管平台,提供了对 Next.js 的最佳支持。它可以无缝处理所有 Next.js 特性,包括静态生成(SSG)、增量静态生成(ISR)、服务端渲染(SSR)等。
  2. 自动化部署和预览:Vercel 支持自动化部署,通过连接 GitHub、GitLab 或 Bitbucket,在每次代码提交时自动进行部署,并提供预览功能。
  3. 全栈功能支持:Vercel 支持全栈功能,包括 API 路由、SSR、ISR 等,可以直接在服务器端处理动态数据。
  4. 优化的开发者体验:Vercel 提供出色的开发者体验,包括实时日志、监控和良好的调试工具。
  5. 快速的构建和全球 CDN:Vercel 提供全球 CDN 来加速静态内容分发,构建速度非常快,特别是在 Next.js 项目上。
缺点:
  1. 免费计划的限制:Vercel 的免费计划对于小型项目足够,但有构建次数和带宽的限制。如果项目流量较大,可能需要升级到付费计划。
  2. 较少的安全功能:相比 Cloudflare,Vercel 提供的安全功能较少,尤其是在 DDoS 防护和 WAF 方面。对于大型项目,可能需要额外的安全配置。
  3. 对 Edge Runtime 的支持较弱:Vercel 主要在服务器上执行代码,对于边缘计算的支持不如 Cloudflare 强大。

3. 特性对比表格

Cloudflare Pages vs Vercel

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 运行时的特点
  1. 全球分布的执行环境:Edge 运行时在全球的边缘节点上执行代码,这些节点通常位于数据中心的边缘,更接近用户,因此可以显著减少请求的延迟。
  2. 无状态:大多数 Edge 运行时是无状态的,也就是说每次请求之间的状态不会被保存,这意味着每个请求都是独立的,需要依赖外部存储或数据库来管理会话和数据。
  3. 轻量和快速:Edge 运行时的环境通常是轻量级的,能够快速启动和执行代码。这使得它非常适合处理小型、快速的任务,比如 API 请求、图像优化、内容缓存和权限验证等。
  4. 局部计算:Edge 运行时可以在用户所在地附近的边缘节点上处理请求,避免了将请求发送到远程服务器,大大减少了网络传输的时间成本。
  5. 安全性:由于代码是在边缘节点上执行的,因此可以增加应用的安全性,减少潜在的攻击面。
Edge 运行时的应用场景
  1. 动态内容交付:通过 Edge 运行时,可以在边缘节点动态生成 HTML、API 响应或数据,从而加快动态内容的加载速度。
  2. 内容缓存:将静态内容缓存到边缘节点,结合动态内容生成,使得用户可以快速访问缓存数据。
  3. 个性化体验:可以根据用户的地理位置、设备类型或其他请求信息,在边缘节点进行个性化处理,比如展示个性化内容或广告。
  4. 安全验证:通过在边缘节点运行验证逻辑,可以在用户接触核心服务器之前进行身份验证、安全检查和访问控制,从而提升系统的整体安全性。
Edge 运行时与传统运行时的区别
  • 传统运行时:通常是在集中式的数据中心运行。用户请求需要经过较长的网络传输才能到达服务器,处理完后再将响应发送回客户端,这种方式对网络传输的延迟比较敏感,特别是对于全球用户来说,延迟可能较高。
  • Edge 运行时:是在用户附近的边缘节点处理请求,减少网络延迟。这种方式特别适合需要低延迟、高并发、实时响应的场景,例如实时数据处理、内容个性化等。
例子
  • Cloudflare Workers:Cloudflare 提供的边缘计算服务,它允许开发者在全球的 Cloudflare 边缘节点上运行 JavaScript、Rust、C++ 或其他语言编写的代码。它被用于处理 API 请求、优化响应、进行身份验证等操作。
  • Vercel Edge Functions:Vercel 提供的 Edge Functions 允许开发者在边缘节点运行 JavaScript/TypeScript 代码,并结合 Next.js 的动态功能,能够显著加速 SSR 和 API 路由的响应速度。
Edge 运行时的挑战
  1. 有限的运行环境:由于边缘节点的资源限制,Edge 运行时通常不支持完整的 Node.js 运行环境。很多传统的 Node.js 模块(如文件系统、进程管理等)在 Edge 运行时无法使用。
  2. 无状态设计:Edge 运行时通常是无状态的,这意味着开发者需要依赖外部服务(如数据库、缓存系统)来存储会话数据或状态信息。
  3. 调试和监控:由于代码分布在多个边缘节点上,调试和监控可能变得更加复杂,开发者需要使用分布式日志和监控工具来跟踪应用的行为。

二、工程适配

以下内容是介绍如何把之前部署在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账号

Cloudflare Pages Next.js Project deploy Step 1

2. 登录Github(GitLab),添加部署的项目

Cloudflare Pages Next.js Project deploy Step 2

3. 新增Github项目

Cloudflare Pages Next.js Project deploy Step 3

4. 配置项目运行环境

在步骤二中,Framework preset 选择Next.js就行,接着直接点“Save and Depoly”进行部署。

Cloudflare Pages Next.js Project deploy Step 4

5. 部署完成

部署成功之后,Cloudflare会给项目配置一个次级域名,点击”XXX.pages.dev”可以直接访问。

Cloudflare Pages Next.js Project deploy Step 5

6. 配置项目域名

在项目的“Custom domains” 模块可以指定项目的域名,到这步所有的操作就都完成了。

Cloudflare Pages Next.js Project deploy Step 6

7. 部署异常

在部署的过程中如果有异常,会在控制台日志中输出,根据提示的日志修改即可。如果问题修改完了,重新部署还是提示同样的问题,直接把问题项目删除,把项目部署步骤从头来一遍。

Cloudflare Pages Next.js Project deploy  Edge Error

四、其他资料参考

我把网站迁移到 cf,省了几万块

扩展阅读:

  • 使用ChatGPT开发Next.js图片转化工具网站
  • XML在线工具及代码开源
博客公众号

微信公众号

转载请注明出处:陈文管的博客 – Cloudflare Pages部署Next.js网站

文章目录

  • 一、Cloudflare Pages 和 Vercel 的对比
    • 1. Cloudflare 部署 Next.js 项目
      • 优点:
      • 缺点:
    • 2. Vercel 部署 Next.js 项目
      • 优点:
      • 缺点:
    • 3. 特性对比表格
    • 4. 适用场景
    • 5. 什么是Edge运行时
      • Edge 运行时的特点
      • Edge 运行时的应用场景
      • Edge 运行时与传统运行时的区别
      • 例子
      • Edge 运行时的挑战
  • 二、工程适配
    • 1. 安装部署依赖
    • 2. 新增配置文件wrangler.toml
    • 3. next.config.mjs 配置修改
    • 4. 修改服务端路由运行时
    • 5.  package.json 配置修改
    • 6. 改造对 fs / http 等 nodejs API 的依赖
      • 6.1 文件读取适配修改
      • 6.2 axios调用适配修改
  • 三、Cloudflare Pages部署
    • 1. 连接登录Github账号
    • 2. 登录Github(GitLab),添加部署的项目
    • 3. 新增Github项目
    • 4. 配置项目运行环境
    • 5. 部署完成
    • 6. 配置项目域名
    • 7. 部署异常
  • 四、其他资料参考
博客公众号

闽ICP备18001825号-1 · Copyright © 2025 · Powered by chenwenguan.com