dalaolala / blog

用issue来写博客 和别人学的
MIT License
71 stars 24 forks source link

利用cloudflare对任意的网站进行反代 #4

Open dalaolala opened 5 years ago

dalaolala commented 5 years ago

代码库在这里

只需要修改index.js 即可

https://github.com/Siujoeng-Lau/Workers-Proxy/blob/master/src/index.js

这里说一下修改步骤

// 网页端要设置的域名.
const upstream = 'www.google.com'

// 移动端要设置的域名
const upstream_mobile = 'www.google.com'

// 要屏蔽的国家和区域.
const blocked_region = [ 'KP', 'SY', 'PK', 'CU']

// IP addresses which you wish to block from using your service.
const blocked_ip_address = ['0.0.0.0', '127.0.0.1']

使用cloudflare的Workers

【Create a Worker】然后复制上面的index.js内容即可

使用自定义域名

1、把域名接入cloudflare,此处步骤省略
2、设置子域名关联workers的【add route】
3、设置子域名的cname到workers给出的子域名(这个子域名可以自定义前缀)

3、设置要关联的子域名,此处一定要用这种格式,否则会不好用
youdomain.com/*

选择要使用的子域名以及workers

注意

cloudflare对workers的免费调用次数是有限制的

每天10万次,一般来讲,是足够用了
zachpay commented 4 years ago

感谢

dalaolala commented 2 years ago

补充新的有效的代码

注意网址不要带https
// Website you intended to retrieve for users.
const upstream = 'www.google.com'
// Custom pathname for the upstream website.
const upstream_path = '/'
// Website you intended to retrieve for users using mobile devices.
const upstream_mobile = 'www.google.com'
// Countries and regions where you wish to suspend your service.
const blocked_region = ['KP', 'SY', 'PK', 'CU']
// IP addresses which you wish to block from using your service.
const blocked_ip_address = ['0.0.0.0', '127.0.0.1']
// Whether to use HTTPS protocol for upstream address.
const https = true
// Whether to disable cache.
const disable_cache = false
// Replace texts.
const replace_dict = {
    '$upstream': '$custom_domain',
    '//google.com': ''
}
addEventListener('fetch', event => {
    event.respondWith(fetchAndApply(event.request));
})
async function fetchAndApply(request) {
    const region = request.headers.get('cf-ipcountry').toUpperCase();
    const ip_address = request.headers.get('cf-connecting-ip');
    const user_agent = request.headers.get('user-agent');
    let response = null;
    let url = new URL(request.url);
    let url_hostname = url.hostname;
    if (https == true) {
        url.protocol = 'https:';
    } else {
        url.protocol = 'http:';
    }
    if (await device_status(user_agent)) {
        var upstream_domain = upstream;
    } else {
        var upstream_domain = upstream_mobile;
    }
    url.host = upstream_domain;
    if (url.pathname == '/') {
        url.pathname = upstream_path;
    } else {
        url.pathname = upstream_path + url.pathname;
    }
    if (blocked_region.includes(region)) {
        response = new Response('Access denied: WorkersProxy is not available in your region yet.', {
            status: 403
        });
    } else if (blocked_ip_address.includes(ip_address)) {
        response = new Response('Access denied: Your IP address is blocked by WorkersProxy.', {
            status: 403
        });
    } else {
        let method = request.method;
        let request_headers = request.headers;
        let new_request_headers = new Headers(request_headers);
        new_request_headers.set('Host', upstream_domain);
        new_request_headers.set('Referer', url.protocol + '//' + url_hostname);
        let original_response = await fetch(url.href, {
            method: method,
            headers: new_request_headers
        })
        connection_upgrade = new_request_headers.get("Upgrade");
        if (connection_upgrade && connection_upgrade.toLowerCase() == "websocket") {
            return original_response;
        }
        let original_response_clone = original_response.clone();
        let original_text = null;
        let response_headers = original_response.headers;
        let new_response_headers = new Headers(response_headers);
        let status = original_response.status;

        if (disable_cache) {
            new_response_headers.set('Cache-Control', 'no-store');
        }
        new_response_headers.set('access-control-allow-origin', '*');
        new_response_headers.set('access-control-allow-credentials', true);
        new_response_headers.delete('content-security-policy');
        new_response_headers.delete('content-security-policy-report-only');
        new_response_headers.delete('clear-site-data');

        if (new_response_headers.get("x-pjax-url")) {
            new_response_headers.set("x-pjax-url", response_headers.get("x-pjax-url").replace("//" + upstream_domain, "//" + url_hostname));
        }

        const content_type = new_response_headers.get('content-type');
        if (content_type != null && content_type.includes('text/html') && content_type.includes('UTF-8')) {
            original_text = await replace_response_text(original_response_clone, upstream_domain, url_hostname);
        } else {
            original_text = original_response_clone.body
        }

        response = new Response(original_text, {
            status,
            headers: new_response_headers
        })
    }
    return response;
}
async function replace_response_text(response, upstream_domain, host_name) {
    let text = await response.text()
    var i, j;
    for (i in replace_dict) {
        j = replace_dict[i]
        if (i == '$upstream') {
            i = upstream_domain
        } else if (i == '$custom_domain') {
            i = host_name
        }
        if (j == '$upstream') {
            j = upstream_domain
        } else if (j == '$custom_domain') {
            j = host_name
        }
        let re = new RegExp(i, 'g')
        text = text.replace(re, j);
    }
    return text;
}
async function device_status(user_agent_info) {
    var agents = ["Android", "iPhone", "SymbianOS", "Windows Phone", "iPad", "iPod"];
    var flag = true;
    for (var v = 0; v < agents.length; v++) {
        if (user_agent_info.indexOf(agents[v]) > 0) {
            flag = false;
            break;
        }
    }
    return flag;
}
dalaolala commented 1 year ago

2023年最新方法如下

点击Workers 和 Page image

点击创建应用程序 image

点击创建Worker image

部署Worker image

编辑代码 image

复制代码

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

// 准备反代的目的域名,域名自己更改为想要的
let target_url = "https://hostloc.com";
// 要替换内容的正则表达式
let target_url_reg = /hostloc\.com/g;

async function handleRequest(request) {
  let url = new URL(request.url);
  url.hostname = new URL(target_url).hostname;

  // 复制请求对象并更新它的属性
  let headers = new Headers(request.headers);
  headers.set("Referer", target_url);
  headers.set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36");

  const param = {
    method: request.method,
    headers: headers,
    body: request.body,
    redirect: "manual"
  }

  let response = await fetch(url, param);

  // 检查响应头中的内容类型
  const contentType = response.headers.get('content-type');
  if (contentType && contentType.includes('text')) {

    // 如果是文本类型,替换响应主体中的URL
    let responseBody = await response.text();
    responseBody = await handleResBody(request,responseBody); 

    // 复制响应对象并更新它的属性
    let headers = await handleResHeader(response); 

    return new Response(responseBody, {
      status: response.status,
      statusText: response.statusText,
      headers: headers
    });
  } else {
    // 如果不是文本类型,直接返回响应对象
    return response;
  }
}

async function handleResBody(request, responseBody){
  responseBody = responseBody.replace(target_url_reg, new URL(request.url).hostname);
  responseBody = responseBody.replace("<head>", '<head>\n<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">');
  responseBody = responseBody.replace("</head>", '<link rel="stylesheet" type="text/css" href="//cdn.jsdelivr.net/gh/lifespy/css-and-js-hub/css/responsive.css">\n</head>');
  responseBody = responseBody.replace("</body>", '<script src="//cdn.jsdelivr.net/gh/lifespy/css-and-js-hub/js/polish.js" type="text/javascript"></script>\n</body>');
  return responseBody;
}

async function handleResHeader(resp){
  let headers = new Headers(resp.headers);
  headers.set('Access-Control-Allow-Origin', '*');
  headers.set('Access-Control-Allow-Methods', 'GET'); 
  headers.set('Access-Control-Allow-Headers', 'Content-Type');
  return headers;
}

点击保存并部署 image

选择已经接入到Cloudflare的域名 image

选择DNS,添加如下解析 image

选择Worker路由 image

选择添加路由 image

添加一个路由 image

点击Production image

添加自定义域 image

至此已经ok,默认的worker域名已被屏蔽,如验证,请科学访问

参考文章地址 https://blog.zmyos.com/rphostloc.html

dalaolala commented 1 year ago
通过CF Worker对json对象进行免费的存储和获取

https://github.com/huhuhang/jsonbase

Xiao-Chuzhang commented 1 year ago

大佬牛逼

wuyueerhao commented 1 year ago

请教一个问题,如果想替换 meta标签,应该怎么实现呢?