Cloudflare(以下简称 CF) 堪称互联网活菩萨,造就一大批高质量的互联网基础技术服务,更难得的是,几乎所有的服务都有对应的免费的套餐,而且出手大方,基本上有足够的容量或请求次数。
CDN
CF 最初闻其大名是 DDoS 防护做得好,以及内容分发网络(CDN)。当前 CF 把这些服务统一起来,整合到 Website 网站中,用户只需要把域名的 nameserver 指向 CF管理中,即可享用这些既快速又安全的服务。
举一个例子,你的网站放在一个小水管的机器中(例如才 1M 带宽),这时就可以通过 CF 的 CDN 来达到加速的目的。虽然 CF 当前并没有针对中国大陆的优化节点,但测试来说,访问速度并不算太慢。而且除了加速的增强外,还有安全、自带 HTTPS 证书等的多种好处。
域名的 nameserver 指向 CF 后,等于以后所有的域名绑定都在 CF 上进行(A 地址、CNAME、TXT 等),相当于 dnspod 的服务。
验证码 Turnstile
Turnstile 用于 CAPTCHA 的验证码服务。不知为何,我调用 Turnstile 总是遇到问题,以至于我不得不放弃 Turnstile 转投谷歌的,甚是遗憾:(
Pages 页面寄存服务
大家都喜欢用 Github Pages 作为博客寄存的服务,国内的 gitee 也有对应的服务,方便简单迅速。但是 Github 的访问总是那么不畅顺,gitee 亲测也是,不太稳定。于是 Cloudflare Pages 也针对 git 发布的页面提供了加速服务,只要你提供 git 的访问权限,即可自动部署发布,域名的话则通过 CNAME 简单绑到 CF。当然你也可以上传静态资源到 CF。
值得一提的是,Pages 可以整合来自 CF 自己的 Web Analytics,也就是不用加入什么百度统计 Google、Analytics 的 JS 脚本,即可网站的访问统计。同理,开启 CDN 的也能够如法炮制。
Workers
Cloudflare Workers 适用于多种场景,包括但不限于静态网站托管、API 代理、实时数据处理、Web 应用程序的后端逻辑等。通过 Workers,开发者可以构建快速、可靠且安全的应用程序和服务。
简单的反向代理服务器
下面利用 Workers 做一个反向代理服务器,也就是一个网站的镜像:
// 反代目标网站.
const upstream = 'www.dalao.pro';
// 反代目标网站的移动版.
const upstream_mobile = 'www.dalao.pro';
// 访问区域黑名单(按需设置).
const blocked_region = ['TK'];
// IP地址黑名单(按需设置).
const blocked_ip_address = ['0.0.0.0', '127.0.0.1'];
// 路径替换.
const replace_dict = {
'$upstream': '$custom_domain',
'//archiveofourown.org': ''
};
addEventListener('fetch', event => event.respondWith(fetchAndApply(event.request)));
async function fetchAndApply(request) {
const region = request.headers.get('cf-ipcountry').toUpperCase();
const ip_address = request.headers.get('cf-connecting-ip');
const user_agent = request.headers.get('user-agent');
let response = null;
let url = new URL(request.url);
let url_host = url.host;
if (url.protocol == 'http:') {
url.protocol = 'https:'
response = Response.redirect(url.href);
return response;
}
if (await device_status(user_agent))
var upstream_domain = upstream;
else
var upstream_domain = upstream_mobile;
url.host = upstream_domain;
if (blocked_region.includes(region))
response = new Response('Access denied: WorkersProxy is not available in your region yet.', { status: 403 });
else if (blocked_ip_address.includes(ip_address))
response = new Response('Access denied: Your IP address is blocked by WorkersProxy.', { status: 403 });
else {
let method = request.method;
let request_headers = request.headers;
let new_request_headers = new Headers(request_headers);
new_request_headers.set('Host', upstream_domain);
new_request_headers.set('Referer', url.href);
let original_response = await fetch(url.href, {
method: method,
headers: new_request_headers
})
let original_response_clone = original_response.clone();
let original_text = null;
let response_headers = original_response.headers;
let new_response_headers = new Headers(response_headers);
let status = original_response.status;
new_response_headers.set('cache-control', 'public, max-age=14400')
new_response_headers.set('access-control-allow-origin', '*');
new_response_headers.set('access-control-allow-credentials', true);
new_response_headers.delete('content-security-policy');
new_response_headers.delete('content-security-policy-report-only');
new_response_headers.delete('clear-site-data');
const content_type = new_response_headers.get('content-type');
if (content_type.includes('text/html') && content_type.includes('UTF-8'))
original_text = await replace_response_text(original_response_clone, upstream_domain, url_host);
else
original_text = original_response_clone.body;
response = new Response(original_text, {
status,
headers: new_response_headers
});
}
return response;
}
async function replace_response_text(response, upstream_domain, host_name) {
let text = await response.text();
var i, j;
for (i in replace_dict) {
j = replace_dict[i];
if (i == '$upstream')
i = upstream_domain;
else if (i == '$custom_domain')
i = host_name;
if (j == '$upstream')
j = upstream_domain;
else if (j == '$custom_domain')
j = host_name;
let re = new RegExp(i, 'g')
text = text.replace(re, j);
}
return text;
}
async function device_status(user_agent_info) {
var agents = ["Android", "iPhone", "SymbianOS", "Windows Phone", "iPad", "iPod"];
var flag = true;
for (var v = 0; v < agents.length; v++) {
if (user_agent_info.indexOf(agents[v]) > 0) {
flag = false;
break;
}
}
return flag;
}
极致的代理
其实,最简单的反向代理是这样的,才几行 js 代码。这是使用 Cloudflare Workers 加速 Oracle Cloud 对象存储。
const REGION = "";
const BUCKET = "";
const NAMESPACE = "";
const BUCKET_URL = `https://objectstorage.${REGION}.oraclecloud.com/n/${NAMESPACE}/b/${BUCKET}/o`;
addEventListener("fetch", (event) => event.respondWith(handle(event)));
async function handle(event) {
const pathname = new URL(event.request.url).pathname;
return fetch(`${BUCKET_URL}${pathname}`);
}
Cloudflare Workers 直接转发请求和响应。
发挥 CDN 缓存的作用
缓存模式下,先使用 Cache API 将请求缓存于 Cloudflare 的 CDN ,再返回响应正文。
const REGION = "";
const BUCKET = "";
const NAMESPACE = "";
const BUCKET_URL = `https://objectstorage.${REGION}.oraclecloud.com/n/${NAMESPACE}/b/${BUCKET}/o`;
addEventListener("fetch", (event) => event.respondWith(handle(event)));
async function handle(event) {
let request = event.request;
if (["GET", "HEAD", "OPTIONS"].includes(request.method)) {
const pathname = new URL(request.url).pathname;
const cache = caches.default;
let response;
if (request.method === "GET") {
// 缓存 GET 请求
response = await cache.match(request);
if (!response) {
response = await fetch(`${BUCKET_URL}${pathname}`);
let headers = Object.fromEntries(new Map(response.headers));
headers["cache-control"] = "public, max-age=14400";
response = new Response(response.body, { ...response, headers });
event.waitUntil(cache.put(request, response.clone()));
}
} else
// 将非 GET 请求直接转发
response = fetch(`${BUCKET_URL}${pathname}`, { method: request.method });
// override 错误信息以避免泄露 bucket 名称
if (response.status === 404)
return new Response("Not found", { status: 404 });
// 允许浏览器直接播放 .mp4 文件而不触发下载
if (pathname.endsWith(".mp4")) {
headers = { "Content-Type": "video/mp4" };
response = new Response(response.body, { ...response.body, headers });
}
return response;
} else
return new Response("Method not allowed", { status: 405 });
}
Workers 有很多想象的空间,大家可以尽情利用:)
R2 对象存储
CF 提供 S3 协议的对象存储,是为 R2 也。可以绑定 CNAME 的域名。
注意,要绑信用卡 or paypal,但是免费。
Email Routing
CloudFlare Email Routing 是一套免费的邮件转发方案,支持Catch-all,可以将任意邮箱转发到任意邮箱。
# catch-all 支持将任意邮箱转发到指定邮箱,并隐藏你的真实邮箱地址
abc@luolei.org -> your-public-mail@gmail.com
edf@luolei.org -> your-public-mail@gmail.com
xyz@luolei.org -> your-public-mail@gmail.com
Cloudflare 的 Workers,支持你根据不同的域名,设置不同的转发规则,比如:
export default {
async email(message, env, ctx) {
// 通过 message.to 判断希望转发到哪个邮箱
// 例如把 ssyy.1984@luoeli.org 转发到 your-secert-mail@gmail.com
let forwardAddress = message.to.includes(".1984")
? "your-secert-mail@gmail.com"
: "your-public-mail@gmail.com";
await message.forward(forwardAddress);
},
};
使用Catch-all方案,理论上可以实现无限多个邮箱地址,有时候我需要注册一些不太重要的境外服务,就会使用这个方案。毕竟网络安全不分国界,境外服务也存在数据泄漏、密码爆破的风险。
结语
CF 还有很多好用的基础服务,就像一个宝藏,等着我们去慢慢发掘。最后,容我说句:CF 谢谢您!