Cloudflare Workers + R2部署Hugo解决方案
Cloudflare Workers + R2部署Hugo网站,突破Workers文件数上限解决方案
下面我将详细解释如何使用 Cloudflare R2 部署 Hugo 网站,包括完整的配置文件和代码示例:
完整解决方案步骤(含详细配置)
1. 创建 R2 存储桶
- 登录 Cloudflare 控制台
- 进入 R2 → 创建桶
- 输入桶名称(如
my-hugo-site
) - 选择 智能分层(默认即可)
2. 上传 Hugo 文件到 R2
wrangler学习文档:https://developers.cloudflare.com/workers/wrangler/
# 安装 R2 命令行工具(如已安装可跳过)
npm install -g wrangler
# 登录 Cloudflare
npx wrangler login
# 递归上传整个 public 目录
npx wrangler r2 object put my-hugo-site/ --directory ./public --recursive
使用 wrangler r2 object put 命令、R2 API、S3 兼容工具(如 s3cmd, awscli)或支持 R2 的图形化工具(如 Cyberduck)将 Hugo 生成的整个 public/ 目录上传到 R2 桶。
# 通过运行以下命令创建存储桶:
npx wrangler r2 bucket create <YOUR_BUCKET_NAME>
# 检查您的存储桶是否已创建
npx wrangler r2 bucket list
运行该命令后,您将看到所有存储桶名称,包括您刚刚创建的存储桶名称。
# 升级wrangler
npm install -g wrangler@4.22.0
# 上传整个目录
npx wrangler r2 object put "docs-maiyi-xyz/" --file ./public/*
# 单个文件上传示例
npx wrangler r2 object put "docs-maiyi-xyz/index.html" --file ./public/index.html
备选方案:使用 S3 兼容 API
如果 Wrangler 仍然有问题,可以使用 AWS CLI 替代:
# 安装 AWS CLI
pip install awscli
# 配置凭据
aws configure set aws_access_key_id YOUR_R2_ACCESS_KEY
aws configure set aws_secret_access_key YOUR_R2_SECRET_KEY
aws configure set default.region auto
# 上传文件
aws s3 sync ./public s3://docs-maiyi-xyz --endpoint-url=https://<YOUR_ACCOUNT_ID>.r2.cloudflarestorage.com
3. 配置 wrangler.toml
在 Hugo 项目根目录创建/修改 wrangler.toml
:
name = "my-hugo-worker"
main = "worker.js" # Worker 入口文件
compatibility_date = "2024-03-01"
[[r2_buckets]]
binding = "ASSETS" # Worker 中使用的变量名,有效的JavaScript变量名
bucket_name = "my-hugo-site" # R2 桶名称
4. 创建 Worker 脚本 (worker.js
)
// 获取文件扩展名对应的 MIME 类型
const getContentType = (filename) => {
const extension = filename.split('.').pop().toLowerCase();
const types = {
html: 'text/html',
css: 'text/css',
js: 'application/javascript',
json: 'application/json',
png: 'image/png',
jpg: 'image/jpeg',
jpeg: 'image/jpeg',
gif: 'image/gif',
svg: 'image/svg+xml',
ico: 'image/x-icon',
txt: 'text/plain',
webp: 'image/webp',
webm: 'video/webm',
mp4: 'video/mp4',
pdf: 'application/pdf',
woff: 'font/woff',
woff2: 'font/woff2'
};
return types[extension] || 'application/octet-stream';
};
// 主请求处理函数
export default {
async fetch(request, env) {
const url = new URL(request.url);
let pathname = url.pathname;
// 处理根路径请求
if (pathname === '/') {
pathname = '/index.html';
}
// 移除路径开头的斜杠
let objectName = pathname.startsWith('/')
? pathname.substring(1)
: pathname;
try {
// 尝试获取请求的文件
const object = await env.ASSETS.get(objectName);
// 文件不存在时的处理
if (!object) {
// 尝试查找 index.html(用于处理目录请求)
if (!objectName.endsWith('/index.html')) {
const altPath = objectName.endsWith('/')
? `${objectName}index.html`
: `${objectName}/index.html`;
const altObject = await env.ASSETS.get(altPath);
if (altObject) {
return buildResponse(altObject, altPath);
}
}
// 返回 404 页面(如果存在)
const notFound = await env.ASSETS.get('404.html');
return notFound
? buildResponse(notFound, '404.html')
: new Response('Not Found', { status: 404 });
}
// 返回找到的文件
return buildResponse(object, objectName);
} catch (err) {
return new Response('Internal Server Error', { status: 500 });
}
}
};
// 构建响应对象
function buildResponse(object, filename) {
const headers = new Headers();
// 设置内容类型
headers.set('Content-Type', getContentType(filename));
// 设置缓存控制(1天)
headers.set('Cache-Control', 'public, max-age=86400');
// 设置 ETag 用于缓存验证
headers.set('ETag', object.httpEtag);
return new Response(object.body, { headers });
}
5. 部署 Worker
# 在 Hugo 项目根目录执行
wrangler deploy
6. 自动化部署脚本 (可选)
创建 deploy.sh
实现一键部署:
#!/bin/bash
# 生成 Hugo 网站
hugo --minify
# 上传到 R2
wrangler r2 object put my-hugo-site/ --directory ./public --recursive
# 部署 Worker
wrangler deploy
运行权限:chmod +x deploy.sh
关键点详解
R2 绑定机制
binding = "ASSETS"
在 TOML 中定义- 在 Worker 中通过
env.ASSETS
访问 - 使用
.get(key)
方法获取文件对象
智能路径处理
- 自动将
/
重定向到/index.html
- 自动处理目录请求(如
/about/
→/about/index.html
) - 自定义 404 页面支持
- 自动将
性能优化
- 自动设置正确的 Content-Type
- 添加 Cache-Control 头(1天缓存)
- ETag 支持缓存验证
错误处理
- 文件不存在时尝试查找 index.html
- 自定义 404 页面
- 500 错误捕获
常见问题解决
Q: 如何更新网站内容?
A: 重新运行 hugo
生成网站后,再次执行上传和部署:
./deploy.sh
Q: 某些文件类型返回错误 Content-Type?
A: 在 getContentType
函数中添加对应的 MIME 类型,例如:
// 添加新类型
avif: 'image/avif',
wasm: 'application/wasm',
Q: 需要自定义重定向规则? A: 在 Worker 中添加路由处理逻辑:
// 在获取文件前添加重定向规则
if (pathname === '/old-page') {
return Response.redirect('https://yoursite.com/new-page', 301);
}
Q: 如何添加自定义域名? A: 在 Cloudflare 控制台:
- Workers & Pages → 你的 Worker → 触发器
- 在 “Custom Domains” 中添加域名
- 在 DNS 设置中添加 CNAME 记录指向 Worker
优势总结
- 突破文件限制:R2 无文件数量限制
- 成本更低:免费额度包含 10GB 存储 + 100 万次/日读取
- 无缝集成:与 Cloudflare CDN 深度集成
- 部署简单:单个 Worker 脚本处理所有请求
- 高性能:边缘网络全球加速
提示:对于大型网站(>1GB),建议使用
rclone
替代wrangler
上传:rclone copy --progress ./public r2:my-hugo-site