aiastia / note

笔记
17 stars 5 forks source link

用Cloudflare Workers 反代加速任意网站教程 #62

Open aiastia opened 2 years ago

aiastia commented 2 years ago

https://github.com/fajarFWD/workersproxy

aiastia commented 2 years ago

// 上游网站的域名 const upstream = 'github.com' // 上游网站的路径 const upstream_path = '/' // 上游网站的移动端域名 const upstream_mobile = 'github.com' // 禁止访问的国家地区 const blocked_region = ['CN', 'KP', 'SY', 'PK', 'CU'] // 禁止使用服务的IP地址 const blocked_ip_address = ['0.0.0.0', '127.0.0.1'] // 是否开启上游网站的https const https = true // 是否关闭缓存 const disable_cache = true // 替换文字 const replace_dict = { '$upstream': '$custom_domain' }

aiastia commented 2 years ago

如果网站使用另一个域名来提供静态资源,则用户可以部署多个Workers-Proxy并配置文本替换。

www.google.com 调用 www.gstatic.com 上的静态资源 部署 Workers-Proxy A 反向代理 www.gstatic.com 部署 Workers-Proxy B 反向代理 www.google.com 为 Workers-Proxy B 配置文本替换:

aiastia commented 2 years ago

const replace_dict = { '$upstream': '$custom_domain', 'www.gstatic.com': '' }

aiastia commented 2 years ago

// 需要反代的地址 const upstream = 'gist.github.com' // 反代地址的子路径 const upstreamPath = '/' // 反代网站的移动端域名 const upstreamMobile = 'gist.github.com'

// 是否使用 https const useHttps = true

// 禁止使用该 worker 的国家代码 const blockedRegion = ['KP', 'SY', 'PK', 'CU']

// 禁止使用该 worker 的 ip 地址 const blockedIp = ['0.0.0.0', '127.0.0.1']

// 是否关闭缓存 const disableCache = false // 替换条件 const contentTypes = [ 'text/plain', 'text/html' ] // 反代网站中其他需要被替换的地址 const replaceDict = { '$upstream': '$workerDomain', }

addEventListener('fetch', event => { event.respondWith(handleRequest(event.request)) })

/**

if (blockedRegion.includes(region.toUpperCase())) { return new Response('Access denied: WorkersProxy is not available in your region yet.', { status: 403 }); }

if (blockedIp.includes(ip)) { return new Response('Access denied: Your IP address is blocked by WorkersProxy.', { status: 403 }); }

const upstreamDomain = isMobile(request.headers.get('user-agent')) ? upstreamMobile : upstream;

// 构建上游请求地址 let url = new URL(request.url); const workerDomain = url.host;

url.protocol = useHttps ? 'https:' : 'http'; url.pathname = url.pathname === '/' ? upstreamPath : upstreamPath + url.pathname; url.host = upstreamDomain;

// 构建上游请求头 const newRequestHeaders = new Headers(request.headers); newRequestHeaders.set('Host', upstreamDomain); newRequestHeaders.set('Referer', url.protocol + '//' + workerDomain);

// 获取上游响应 const originalResponse = await fetch(url.href, { method: request.method, headers: newRequestHeaders })

const connectionUpgrade = newRequestHeaders.get("Upgrade"); if (connectionUpgrade && connectionUpgrade.toLowerCase() === "websocket") { return originalResponse; }

let originalResponseClone = originalResponse.clone();

// 构建响应头 let responseHeaders = originalResponseClone.headers; let newResponseHeaders = buildResponseHeaders(responseHeaders); if (newResponseHeaders.get("x-pjax-url")) { newResponseHeaders.set("x-pjax-url", responseHeaders.get("x-pjax-url").replace("//" + upstreamDomain, "//" + workerDomain)); }

// 构建响应体 let originalText; const contentType = newResponseHeaders.get('content-type'); if (contentType != null) { const types = contentType.replace(' ','').split(';') if (types.includes('charset=utf-8')){ for (let i of contentTypes) { if (types.includes(i)){ originalText = await replaceResponseText(originalResponseClone, upstreamDomain, workerDomain); break } } } } else { originalText = originalResponseClone.body }

return new Response(originalText, { status: originalResponseClone.status, headers: newResponseHeaders }) }

function isMobile(userAgent) { userAgent = userAgent || '' let agents = ["Android", "iPhone", "SymbianOS", "Windows Phone", "iPad", "iPod"]; for (let v = 0; v < agents.length; v++) { if (userAgent.indexOf(agents[v]) > 0) { return true; } } }

function buildResponseHeaders(originalHeaders) { const result = new Headers(originalHeaders); if (disableCache) { result.set('Cache-Control', 'no-store'); } result.set('access-control-allow-origin', '*'); result.set('access-control-allow-credentials', true); result.delete('content-security-policy'); result.delete('content-security-policy-report-only'); result.delete('clear-site-data');

return result }

async function replaceResponseText(response, upstreamDomain, workerDomain) { let text = await response.text() const placeholders = { "$upstream": upstreamDomain, "$workerDomain": workerDomain }

for (let origin in replaceDict) { let target = replaceDict[origin]

origin = placeholders[origin] || origin target = placeholders[target] || target

const re = new RegExp(origin, 'g') text = text.replace(re, target); }

return text; }