首页
Search
1
Sublime Text 4 正式版发布了,自己动手注册激活以及汉化
536 阅读
2
Lark飞书国际版,免费邮局支持50用户,200GB容量,可SMTP发信
262 阅读
3
Windows激活之路:通过HWIDGen申请永久数字许可证
204 阅读
4
甲骨文云(Oracle Cloud)免费开通ARM云服务器
202 阅读
5
Windows激活之路:将Windows 10 LTSC转成Win10专业版激活
178 阅读
网络资讯
技术教程
活动线报
VPS主机
实用工具
随手小记
登录
Search
标签搜索
VPS
服务器
腾讯云
免费
域名
阿里云
数据库
优惠券
Cloudflare
Github
中国联通
代金券
Docker
中国移动
chrome
JetBrains
Linux
Xshell
百度网盘
联通
小 萌
累计撰写
266
篇文章
累计收到
0
条评论
首页
栏目
网络资讯
技术教程
活动线报
VPS主机
实用工具
随手小记
页面
搜索到
1
篇与
的结果
2019-07-18
利用CloudFlare Worker 免费部署 JSProxy 服务
全篇转载自 @如有乐享 ,由 小萌 进行编辑,本文仅作存档使用JSProxy 一个基于浏览器端 JS 实现的在线代理,这里不多介绍!本文主要介绍一下利用CloudFlare Worker 来搭建一个JSProxy服务。CloudFlare Worker 是 CloudFlare 的边缘计算服务。开发者可通过 JavaScript 对 CDN 进行编程,从而能灵活处理 HTTP 请求。这使得很多任务可在 CDN 上完成,无需自己的服务器参与。CFW免费服务,支持每天10 万次免费请求!基本也够用了!项目介绍项目地址:https://github.com/EtherDream/jsproxy准备工作Cloudflare 账号一个使用教程1)打开 https://workers.cloudflare.com,登陆上你的 Cloudflare 账号激活 Workers 服务然后创建一个 Workers【Create a Worker】2)修改一下子域名,创建出来的域名格式 自定义的内容.Cloudflare用户名.workers.dev3)复制 https://raw.githubusercontent.com/EtherDream/jsproxy/master/cf-worker/index.js 的内容到左侧代码(Script)区域文章最下方有代码备份!!4)先点击【Run】右侧看执行效果,再点击 【Save and deploy】 部署代码5)届时你可以访问你的站点https://xxx.子域名.workers.dev查看效果进入站点后将线路选择切换为当前站点即可使用特别提示:浏览网站的时候,有时候会提示加载不安全脚本,点击允许即可!代码备份'use strict' /** * static files (404.html, sw.js, conf.js) */ const ASSET_URL = 'https://zjcqoo.github.io' const JS_VER = 8 const MAX_RETRY = 1 const PREFLIGHT_INIT = { status: 204, headers: new Headers({ 'access-control-allow-origin': '*', 'access-control-allow-methods': 'GET,POST,PUT,PATCH,TRACE,DELETE,HEAD,OPTIONS', 'access-control-allow-headers': '--raw-info,--level,--url,--referer,--cookie,--origin,--ext,--aceh,--ver,--type,--mode,accept,accept-charset,accept-encoding,accept-language,accept-datetime,authorization,cache-control,content-length,content-type,date,if-match,if-modified-since,if-none-match,if-range,if-unmodified-since,max-forwards,pragma,range,te,upgrade,upgrade-insecure-requests,x-requested-with,chrome-proxy,purpose', 'access-control-max-age': '1728000', }), } /** * @param {string} message * @param {number} status * @param {any} headers */ function makeRes(message, status = 200, headers = {}) { headers['cache-control'] = 'no-cache' headers['vary'] = '--url' headers['access-control-allow-origin'] = '*' return new Response(message, {status, headers}) } addEventListener('fetch', e => { const ret = fetchHandler(e) .catch(err => makeRes('cfworker error:' + err, 502)) e.respondWith(ret) }) function fetchHandler(e) { const req = e.request const urlStr = req.url const urlObj = new URL(urlStr) if (urlObj.protocol === 'http:') { urlObj.protocol = 'https:' return makeRes('', 301, { 'strict-transport-security': 'max-age=99999999; includeSubDomains; preload', 'location': urlObj.href, }) } switch (urlObj.pathname) { case '/http': return httpHandler(req) case '/ws': return makeRes('not support', 400) case '/works': return makeRes('it works') default: // static files return fetch(ASSET_URL + urlObj.pathname) } } /** * @param {Request} req */ async function httpHandler(req) { const reqHdrRaw = req.headers if (reqHdrRaw.has('x-jsproxy')) { return Response.error() } // preflight if (req.method === 'OPTIONS' && reqHdrRaw.has('access-control-request-headers') ) { return new Response(null, PREFLIGHT_INIT) } let urlObj = null let extHdrs = null let acehOld = false let rawSvr = '' let rawLen = '' let rawEtag = '' const reqHdrNew = new Headers(reqHdrRaw) reqHdrNew.set('x-jsproxy', '1') for (const [k, v] of reqHdrRaw.entries()) { if (!k.startsWith('--')) { continue } reqHdrNew.delete(k) const k2 = k.substr(2) switch (k2) { case 'url': urlObj = new URL(v) break case 'aceh': acehOld = true break case 'raw-info': [rawSvr, rawLen, rawEtag] = v.split('|') break case 'level': case 'mode': case 'type': break case 'ext': extHdrs = JSON.parse(v) break default: if (v) { reqHdrNew.set(k2, v) } else { reqHdrNew.delete(k2) } break } } if (extHdrs) { for (const [k, v] of Object.entries(extHdrs)) { reqHdrNew.set(k, v) } } if (!urlObj) { return makeRes('missing url param', 403) } /** @type {RequestInit} */ const reqInit = { method: req.method, headers: reqHdrNew, } if (req.method === 'POST') { reqInit.body = req.body } return proxy(urlObj, reqInit, acehOld, rawLen, 0) } /** * * @param {URL} urlObj * @param {RequestInit} reqInit * @param {number} retryTimes */ async function proxy(urlObj, reqInit, acehOld, rawLen, retryTimes) { const res = await fetch(urlObj.href, reqInit) const resHdrOld = res.headers const resHdrNew = new Headers(resHdrOld) let expose = '*' let vary = '--url' for (const [k, v] of resHdrOld.entries()) { if (k === 'access-control-allow-origin' || k === 'access-control-expose-headers' || k === 'location' || k === 'set-cookie' ) { const x = '--' + k resHdrNew.set(x, v) if (acehOld) { expose = expose + ',' + x } resHdrNew.delete(k) } else if (k === 'vary') { vary = vary + ',' + v } else if (acehOld && k !== 'cache-control' && k !== 'content-language' && k !== 'content-type' && k !== 'expires' && k !== 'last-modified' && k !== 'pragma' ) { expose = expose + ',' + k } } if (acehOld) { expose = expose + ',--s' resHdrNew.set('--t', '1') } // verify if (rawLen) { const newLen = resHdrOld.get('content-length') || '' const badLen = (rawLen !== newLen) if (badLen) { if (retryTimes < MAX_RETRY) { urlObj = await parseYtVideoRedir(urlObj, newLen, res) if (urlObj) { return proxy(urlObj, reqInit, acehOld, rawLen, retryTimes + 1) } } return makeRes('error', 400, { '--error': 'bad len:' + newLen }) } if (retryTimes > 1) { resHdrNew.set('--retry', retryTimes) } } let status = res.status resHdrNew.set('access-control-expose-headers', expose) resHdrNew.set('access-control-allow-origin', '*') resHdrNew.set('vary', vary) resHdrNew.set('--s', status) resHdrNew.set('--ver', JS_VER) resHdrNew.delete('content-security-policy') resHdrNew.delete('content-security-policy-report-only') if (status === 301 || status === 302 || status === 303 || status === 307 || status === 308 ) { status = status + 10 } return new Response(res.body, { status, headers: resHdrNew, }) } /** * @param {URL} urlObj */ function isYtUrl(urlObj) { return ( urlObj.host.endsWith('.googlevideo.com') && urlObj.pathname.startsWith('/videoplayback') ) } /** * @param {URL} urlObj * @param {number} newLen * @param {Response} res */ async function parseYtVideoRedir(urlObj, newLen, res) { if (newLen > 2000) { return null } if (!isYtUrl(urlObj)) { return null } try { const data = await res.text() urlObj = new URL(data) } catch (err) { return null } if (!isYtUrl(urlObj)) { return null } return urlObj }
2019年07月18日
3 阅读
0 评论
0 点赞