文章摘要
猿_AI

[!CAUTION]
Cloudflare 已经更新相关 ToS,本文介绍的内容会违反 ToS 限制。有可能导致封号,请勿参考。

需求背景

在国内,有很多互联网的服务用起来并不爽,很多时候会遇到网站打开了,图片死活加载不出来或者加载到一半就不加载了。比如 Gravatar 的图像服务,又比如 Fanza 的图片。在终端不用 Proxy 的前提下,解决这个问题,需要做一个反向代理来实现。

为什么用 Cloudflare

  • 我的域名在 Cloudflare
  • Cloudflare Workers 有免费额度
  • Cloudflare KV 有免费额度
  • Cloudflare 全球都有服务器,比一般自己搭建的牛逼多了
  • 我不想自己开 nginx 实现

综上,这就是为什么使用 Cloudflare 的 Workers 和 KV 服务来实现了。

流程逻辑

flow

具体步骤

准备动作

  • 准备一个能够正常访问的域名;
  • 能够正常访问 Cloudflare 的网络条件
  • Cloudflare 账号
  • gooreplacer 插件

开启 KV

操作步骤以英文界面为准,因为 Cloudflare 的中文翻译太垃圾了。

创建 namespaces

  • 点击 “Workers & Pages”
  • 点击 “KV”
  • 点击 “Create a namespaces”
    KV_0001
  • 在 “Namespace Name” 输入 “RVCACHE” (RVCACHE 可自己改成想要的名字)
  • 点击 “Add”
    KV_0002

创建 Workers

  • 点击 “Workers & Pages”
  • 点击 “Overview”
  • 点击 “Create”
    WK_0001
  • 点击 “Create Worker”
    WK_0002
  • “Name your project” 输入你的项目名字
  • 点击 “SAVE”
  • 点击 “Finish”
    WK_0003

Workers 绑定 KV

  • 点击创建的 Workers
  • 点击 “Setting”
  • 点击 “Variables”
  • 找到 “KV Namespace Bindings”
  • 点击 “Add binding”
    BD_0001
  • “Variable name” 输入 “RVCACHE”
  • “KV Namespace” 点击 “select” 选择刚才创建的 “RVCACHE”
  • 点击 “Deploy”
    BD_0002

编写代码

  • 点击 “Edit Code”
    ED_0001
  • 粘贴以下代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
// 定义路径映射
const PATH_MAP = {
"/gravatar": "https://secure.gravatar.com",
};

async function handleRequest(request) {
const url = new URL(request.url);
const pathParts = url.pathname.split('/');
const route = `/${pathParts[1]}`;

const originBase = PATH_MAP[route];

if (!originBase) {
// 如果请求的路径不在映射表中,返回 404
return new Response('Route not mapped', { status: 404 });
}

// 构建 cacheKey 和 originUrl
const cacheKey = `${route}${url.pathname.replace(route, '')}`;
const originUrl = `${originBase}${url.pathname.replace(route, '')}`;

// 从 KV 中检查缓存
const cache = await REVERSE_CACHE.get(cacheKey, { type: 'arrayBuffer' });

if (cache) {
// 返回缓存的响应
return new Response(cache, {
headers: {
'Content-Type': 'application/octet-stream',
'X-Worker-Cache': 'HIT'
}
});
}

// 如果缓存中没有,则从 origin 获取
const response = await fetch(originUrl);

if (response.ok) {
const contentType = response.headers.get('Content-Type');

// 检查是否为常见图片类型
if (contentType && (contentType.includes('image/jpeg') || contentType.includes('image/png') || contentType.includes('image/gif'))) {
const responseData = await response.arrayBuffer();
// 缓存响应
await REVERSE_CACHE.put(cacheKey, responseData, { expirationTtl: 86400 }); // 缓存一天

return new Response(responseData, {
headers: {
'Content-Type': contentType,
'X-Worker-Cache': 'MISS'
}
});
} else {
// 不是常见图片类型,不缓存,直接返回
return response;
}
} else {
return new Response('Not found', { status: 404 });
}
}

addEventListener('fetch', event => {
event.respondWith(handleRequest(event.request));
});
  • 点击 “Deploy”
    ED_0002
  • 点击 “Save and deploy”
    ED_0003

Workers 绑定域名

  • 点击 “Setting”
  • 点击 “Triggers”
  • “Custom Domains” 点击 “Add Custom Domain”
  • “Domain” 输入自己的域名
  • 点击 “Add Custom Domain”
    AD_0001

浏览器插件配置

其他备注

  1. 多路径支持,参照写法多加一行即可;
  2. 上述代码是使用 OpenAI 的 ChatGPT 写的。