通过cloudflare 实现反向代理
说明
参考项目:https://github.com/ymyuuu/Cloudflare-Workers-Proxy?tab=readme-ov-file
通过创建一个 workers 来实现反向代理。
作用
- 绕过图片反盗链限制
- 绕过国内网站封禁
魔改版 - 微信公众号图片反盗链突破
- 访问我的域名,自动跳转到https://mmbiz.qpic.cn
- 去掉了请求头中的的 referer
- 修改了原始响应内容,访问首页直接跳转到 博客首页
addEventListener('fetch', event => {
event.respondWith(handleRequest(event.request));
});
async function handleRequest(request) {
try {
const url = new URL(request.url);
// 如果访问根目录,返回HTML
if (url.pathname === "/") {
return new Response(getRootHtml(), {
headers: {
'Content-Type': 'text/html; charset=utf-8'
}
});
}
// 从请求路径中提取目标 URL
let actualUrlStr = decodeURIComponent(url.pathname.replace("/", ""));
// 判断用户输入的 URL 是否带有协议
actualUrlStr = `https://mmbiz.qpic.cn/${actualUrlStr}`
// 保留查询参数
actualUrlStr += url.search;
// 创建新 Headers 对象,排除以 'cf-'和 'referer' 开头的请求头
const newHeaders = filterHeaders(request.headers, name => !name.toLowerCase().startsWith('cf-') && name.toLowerCase() !== 'referer');
// 创建一个新的请求以访问目标 URL
const modifiedRequest = new Request(actualUrlStr, {
headers: newHeaders,
method: request.method,
body: request.body,
redirect: 'manual'
});
// 发起对目标 URL 的请求
const response = await fetch(modifiedRequest);
let body = response.body;
// 处理重定向
if ([301, 302, 303, 307, 308].includes(response.status)) {
body = response.body;
// 创建新的 Response 对象以修改 Location 头部
return handleRedirect(response, body);
} else if (response.headers.get("Content-Type")?.includes("text/html")) {
body = await handleHtmlContent(response, url.protocol, url.host, actualUrlStr);
}
// 创建修改后的响应对象
const modifiedResponse = new Response(body, {
status: response.status,
statusText: response.statusText,
headers: response.headers
});
// 添加禁用缓存的头部
setNoCacheHeaders(modifiedResponse.headers);
// 添加 CORS 头部,允许跨域访问
setCorsHeaders(modifiedResponse.headers);
return modifiedResponse;
} catch (error) {
// 如果请求目标地址时出现错误,返回带有错误消息的响应和状态码 500(服务器错误)
return jsonResponse({
error: error.message
}, 500);
}
}
// 确保 URL 带有协议
function ensureProtocol(url, defaultProtocol) {
return url.startsWith("http://") || url.startsWith("https://") ? url : defaultProtocol + "//" + url;
}
// 处理重定向
function handleRedirect(response, body) {
const location = new URL(response.headers.get('location'));
const modifiedLocation = `/${encodeURIComponent(location.toString())}`;
return new Response(body, {
status: response.status,
statusText: response.statusText,
headers: {
...response.headers,
'Location': modifiedLocation
}
});
}
// 处理 HTML 内容中的相对路径
async function handleHtmlContent(response, protocol, host, actualUrlStr) {
const originalText = await response.text();
const regex = new RegExp('((href|src|action)=["\'])/(?!/)', 'g');
let modifiedText = replaceRelativePaths(originalText, protocol, host, new URL(actualUrlStr).origin);
return modifiedText;
}
// 替换 HTML 内容中的相对路径
function replaceRelativePaths(text, protocol, host, origin) {
const regex = new RegExp('((href|src|action)=["\'])/(?!/)', 'g');
return text.replace(regex, `$1${protocol}//${host}/${origin}/`);
}
// 返回 JSON 格式的响应
function jsonResponse(data, status) {
return new Response(JSON.stringify(data), {
status: status,
headers: {
'Content-Type': 'application/json; charset=utf-8'
}
});
}
// 过滤请求头
function filterHeaders(headers, filterFunc) {
return new Headers([...headers].filter(([name]) => filterFunc(name)));
}
// 设置禁用缓存的头部
function setNoCacheHeaders(headers) {
headers.set('Cache-Control', 'no-store');
}
// 设置 CORS 头部
function setCorsHeaders(headers) {
headers.set('Access-Control-Allow-Origin', '*');
headers.set('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');
headers.set('Access-Control-Allow-Headers', '*');
}
// 返回根目录的 HTML
function getRootHtml() {
return `<!DOCTYPE html>
<meta http-equiv="Refresh" content="0; url=https://blog.gm7.org">
</html>`;
}
效果: