{
"title": "我是如何解决 jsDelivr 在国内被污染的?",
"tags": [
"post",
"Cloudflare",
"jsDelivr"
],
"summary": "早在2021年12月20日,jsDelivr 在中国大陆地区的 ICP 备案被吊销,且随后的服务在中国大陆地区极不稳定,严重拖慢了网页的速度。 由于 jsDelivr 被封锁,导致了原来使用 jsDelivr 的 CDN 服务的网页速度缓慢,多数功能不正常。要解决这个问题…",
"sources": [
"xlog"
],
"external_urls": [
"https://xlog.yct.ee/jsDelivrOnCloudflare"
],
"date_published": "2023-04-06T12:20:14.000Z",
"content": "---\ntitle: 我是如何解决 jsDelivr 在国内被污染的?\nabbrlink: 'jsDelivr'\ntags:\n - Cloudflare\ncategories: 技术\nmathjax: true\ndate: 2023-04-06 12:20:14\ndescription: 使用Cloudflare Worker为jsDelivr搭建反向代理服务\nsticky: 2\n---\n早在2021年12月20日,jsDelivr 在中国大陆地区的 ICP 备案被吊销,且随后的服务在中国大陆地区极不稳定,严重拖慢了网页的速度。\n\n由于 jsDelivr 被封锁,导致了原来使用 jsDelivr 的 CDN 服务的网页速度缓慢,多数功能不正常。要解决这个问题,要么更换 CDN,要么给 jsDelivr 套上一层反向代理。这里博主采用了 Cloudflare Worker。\n# 新建 Worker\n登录到 Cloudflare 控制台,点击侧栏的 Workers,新建服务。\n\n![gh](https://cdn.yct.ee/gh/BarryYangi/ObsStaticData@main/obsidian/16807536030001yhgo9.png)\n\n在创建页面填入你自己的服务名称。\n![gh](https://cdn.yct.ee/gh/BarryYangi/ObsStaticData@main/obsidian/1680753650000qwb9pf.png)\n\n创建后将转入资源页面。\n![gh](https://cdn.yct.ee/gh/BarryYangi/ObsStaticData@main/obsidian/1680753684000wpls1p.png)\n\n# 部署\n点击“快速编辑”,在代码框内复制以下代码:\n\n```javascript\n// 替换成你想镜像的站点\nconst upstream = 'cdn.jsdelivr.net'\n \n// 如果那个站点有专门的移动适配站点,否则保持和上面一致\nconst upstream_mobile = 'cdn.jsdelivr.net'\n \nconst blocked_region = ['KP','RU']\n \nconst blocked_ip_address = ['0.0.0.0', '127.0.0.1']\n \nconst replace_dict = {\n '$upstream': '$custom_domain',\n '//cdn.jsdelivr.net': ''\n}\n \n//以下内容都不用动\naddEventListener('fetch', event => {\n event.respondWith(fetchAndApply(event.request));\n})\n \nasync function fetchAndApply(request) {\n \n const region = request.headers.get('cf-ipcountry').toUpperCase();\n const ip_address = request.headers.get('cf-connecting-ip');\n const user_agent = request.headers.get('user-agent');\n \n let response = null;\n let url = new URL(request.url);\n let url_host = url.host;\n \n if (url.protocol == 'http:') {\n url.protocol = 'https:'\n response = Response.redirect(url.href);\n return response;\n }\n \n if (await device_status(user_agent)) {\n upstream_domain = upstream\n } else {\n upstream_domain = upstream_mobile\n }\n \n url.host = upstream_domain;\n \n if (blocked_region.includes(region)) {\n response = new Response('Access denied: WorkersProxy is not available in your region yet.', {\n status: 403\n });\n } else if(blocked_ip_address.includes(ip_address)){\n response = new Response('Access denied: Your IP address is blocked by WorkersProxy.', {\n status: 403\n });\n } else{\n let method = request.method;\n let request_headers = request.headers;\n let new_request_headers = new Headers(request_headers);\n \n new_request_headers.set('Host', upstream_domain);\n new_request_headers.set('Referer', url.href);\n \n let original_response = await fetch(url.href, {\n method: method,\n headers: new_request_headers\n })\n \n let original_response_clone = original_response.clone();\n let original_text = null;\n let response_headers = original_response.headers;\n let new_response_headers = new Headers(response_headers);\n let status = original_response.status;\n \n new_response_headers.set('access-control-allow-origin', '*');\n new_response_headers.set('access-control-allow-credentials', true);\n new_response_headers.delete('content-security-policy');\n new_response_headers.delete('content-security-policy-report-only');\n new_response_headers.delete('clear-site-data');\n \n const content_type = new_response_headers.get('content-type');\n if (content_type.includes('text/html') && content_type.includes('UTF-8')) {\n original_text = await replace_response_text(original_response_clone, upstream_domain, url_host);\n } else {\n original_text = original_response_clone.body\n }\n \n response = new Response(original_text, {\n status,\n headers: new_response_headers\n })\n }\n return response;\n}\n \nasync function replace_response_text(response, upstream_domain, host_name) {\n let text = await response.text()\n \n var i, j;\n for (i in replace_dict) {\n j = replace_dict[i]\n if (i == '$upstream') {\n i = upstream_domain\n } else if (i == '$custom_domain') {\n i = host_name\n }\n \n if (j == '$upstream') {\n j = upstream_domain\n } else if (j == '$custom_domain') {\n j = host_name\n }\n \n let re = new RegExp(i, 'g')\n text = text.replace(re, j);\n }\n return text;\n}\n \nasync function device_status (user_agent_info) {\n var agents = [\"Android\", \"iPhone\", \"SymbianOS\", \"Windows Phone\", \"iPad\", \"iPod\"];\n var flag = true;\n for (var v = 0; v < agents.length; v++) {\n if (user_agent_info.indexOf(agents[v]) > 0) {\n flag = false;\n break;\n }\n }\n return flag;\n}\n```\n\n保存并部署后,你的反向代理就生效了。\n# 自定义域名\n但是不幸的是在国内 `.workers.dev` 后缀的域名现在也被污染了,所以你需要自己绑定一个域名在国内才能正常访问。\n先购买一个域名,然后将其 DNS 服务商转到 cloudflare。随后来到我们刚刚新建的 Workers 管理页面点击触发器->自定义域->添加自定义域,输入你想绑定的域名即可。\n\n# 测试\n使用时,将原来的 `cdn.jsdelivr.net` 域名替换为您的 Worker 或者博主提供的 Worker 就可以了。如:\n```javascript\nhttps://cdn.jsdelivr.net/gh/BarryYangi/ObsStaticData/obsidian/168069442100071iy8i.png\n```\n将`cdn.jsdelivr.net`替换为我们的Worker:\n```javascript\nhttps://jsdelivr-cdn.2059484047.workers.dev/gh/BarryYangi/ObsStaticData/obsidian/168069442100071iy8i.png\n```\n\n这样,就能保证较为稳定的使用 jsDelivr 的服务了。\n\nJust enjoy it.",
"attributes": [
{
"value": "jsDelivrOnCloudflare",
"trait_type": "xlog_slug"
}
]
}