小樱 发表于 2022/3/19 06:15

Cloudflare cf使用workers搭建一个简单的免费页面反代系统,不符合HTTP协议标准规范但是能凑合用,腾讯云函数已经收费

Cloudflare cf使用workers搭建一个简单的免费页面反代系统,不符合HTTP协议标准规范但是能凑合用,腾讯云函数已经收费

比如说,刚刚更新了下方代码,符合HTTP协议标准,已经支持响应206状态码
放入workers即可使用,无需更改。注意绑定自己的自定义域名。

addEventListener('fetch', event => {
    event.passThroughOnException()

    event.respondWith(handleRequest(event))
})

/**
* Respond to the request
* @param {Request} request
*/
async function handleRequest(event) {
    const { request } = event;

    //请求头部、返回对象
    let reqHeaders = new Headers(request.headers),
      outBody, outStatus = 200, outStatusText = 'OK', outCt = null, outHeaders = new Headers({
            "Access-Control-Allow-Origin": reqHeaders.get('Origin'),
            "Access-Control-Allow-Methods": "GET, POST, PUT, PATCH, DELETE, OPTIONS",
            "Access-Control-Allow-Headers": reqHeaders.get('Access-Control-Allow-Headers') || "Accept, Authorization, Cache-Control, Content-Type, DNT, If-Modified-Since, Keep-Alive, Origin, User-Agent, X-Requested-With, Token, x-access-token, Notion-Version"
      });

    try {
      //取域名第一个斜杠后的所有信息为代理链接
      let url = request.url.substr(8);
      url = decodeURIComponent(url.substr(url.indexOf('/') + 1));

      //需要忽略的代理
      if (request.method == "OPTIONS" && reqHeaders.has('access-control-request-headers')) {
            //输出提示
            return new Response(null, PREFLIGHT_INIT)
      }
      else if(url.length < 3 || url.indexOf('.') == -1 || url == "favicon.ico" || url == "robots.txt") {
            return Response.redirect('https://baidu.com', 301)
      }
      //阻断
      else if (blocker.check(url)) {
            return Response.redirect('https://baidu.com', 301)
      }
      else {
            //补上前缀 http://
            url = url.replace(/https:(\/)*/,'https://').replace(/http:(\/)*/, 'http://')
            if (url.indexOf("://") == -1) {
                url = "http://" + url;
            }
            //构建 fetch 参数
            let fp = {
                method: request.method,
                headers: {}
            }

            //保留头部其它信息
            let he = reqHeaders.entries();
            for (let h of he) {
                if (!['content-length'].includes(h)) {
                  fp.headers] = h;
                }
            }
            // 是否带 body
            if (["POST", "PUT", "PATCH", "DELETE"].indexOf(request.method) >= 0) {
                const ct = (reqHeaders.get('content-type') || "").toLowerCase();
                if (ct.includes('application/json')) {
                      let requestJSON = await request.json()
                      console.log(typeof requestJSON)
                  fp.body = JSON.stringify(requestJSON);
                } else if (ct.includes('application/text') || ct.includes('text/html')) {
                  fp.body = await request.text();
                } else if (ct.includes('form')) {
                  fp.body = await request.formData();
                } else {
                  fp.body = await request.blob();
                }
            }
            // 发起 fetch
            let fr = (await fetch(url, fp));
            outCt = fr.headers.get('content-type');
            if(outCt && (outCt.includes('application/text') || outCt.includes('text/html'))) {
            try {
                // 添加base
                let newFr = new HTMLRewriter()
                .on("head", {
                  element(element) {
                  element.prepend(`<base href="${url}" />`, {
                      html: true
                  })
                  },
                })
                .transform(fr)
                fr = newFr
            } catch(e) {
            }
            }

            for (const of fr.headers.entries()) {
            outHeaders.set(key, value);
            }

            outStatus = fr.status;
            outStatusText = fr.statusText;
            outBody = fr.body;
      }
    } catch (err) {
      outCt = "application/json";
      outBody = JSON.stringify({
            code: -1,
            msg: JSON.stringify(err.stack) || err
      });
    }

    //设置类型
    if (outCt && outCt != "") {
      outHeaders.set("content-type", outCt);
    }

    let response = new Response(outBody, {
      status: outStatus,
      statusText: outStatusText,
      headers: outHeaders
    })

    return response;

    // return new Response('OK', { status: 200 })
}

/**
* 阻断器
*/
const blocker = {
    keys: [".m3u8", ".ts", ".acc", ".m4s", "photocall.tv", "googlevideo.com"],
    check: function (url) {
      url = url.toLowerCase();
      let len = blocker.keys.filter(x => url.includes(x)).length;
      return len != 0;
    }
}


workers反代使用方式
https://workers绑定的自定义域名/https://bmd.itzmx.com/static/image/common/logo.png


反代支持301跳转跟随来始终以https发起,目标域名不带http和带http均为http发起(如果301则为https发起),目标带https时候则强制以https发起(会校验TLS证书有效性,不允许反代目标域名为自签名)
cf反代回源站所传递的ip地址:2a06:98c0:3600::103
Cloudflare customer zone, the CF-Connecting-IP value will be set to the Worker client IP address '2a06:98c0:3600::103' for security reasons.
数据来自官方文档:https://developers.cloudflare.com/workers/runtime-apis/headers/

提醒,请勿滥用,cf反代服务器每天限量10W次下载,每日早晨8点刷新配额。
CF反代代码没做ip地址支持,仅支持域名,反代能访问 1.1.1.1 1.1.1.2 1.1.1.3 1.0.0.1 1.0.0.2 1.0.0.3 这几个ip,其它ip都不允许直接访问
https://反代地址/https://1.1.1.1/cdn-cgi/trace 可以改成这样用来检测cf反代在线状态,非200状态码代表无法使用。反代超10W每日配额时是输出429状态码。

腾讯云函数也可以实现相同的效果:https://curl.qcloud.com/W4ANcAUL
但是收费了就不介绍了。


自己有服务器,想用kangle搭建一个网络更快的,只需操作文章中说的“国内服务器"
https://bbs.itzmx.com/thread-100060-1-1.html

用kangle自建时建议hosts文件绑定国内备案域名用国内反代服务器,需要使用https,例如反代地址 pikpak.oss-cn-hangzhou.aliyuncs.com 证书文件要在电脑上受信一下
https://bbs.itzmx.com/thread-90800-1-1.html

一个生成的证书例子:https://bbs.itzmx.com/thread-90896-1-1.html

既然有反代那就要有屏蔽的方法
网站屏蔽Cloudflare cf使用workers搭建的反代爬虫bot,REMOTE_ADDR header头部禁止 2a06:98c0:3600::103 ipv6地址,非真实浏览器禁止访问
https://bbs.itzmx.com/thread-101376-1-1.html

oitre 发表于 2022/3/19 15:28

小樱啥时候出个比特彗星下载百度网盘的完整教程鸭
页: [1]
查看完整版本: Cloudflare cf使用workers搭建一个简单的免费页面反代系统,不符合HTTP协议标准规范但是能凑合用,腾讯云函数已经收费