偶然看到一个利用 Cloudflare Workers 做镜像的方法,无须购买服务器了,留作备用。
GitHub 项目:https://github.com/Siujoeng-Lau/Workers-Proxy

  1. 如果已经注册了 Cloudflare 账号,直接在左上 Products->Workers,没有就注册一个账号再说。
  2. 填写一个唯一子域名,Set up
  3. 选择免费版:
  4. 点击 Create a Worker 创建一个 Worker:
  5. 自动生成一串名称,有 hello world 示例代码:
  6. 删除示例,拷贝下方代码,看预览,保存部署:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    // 代理网站.
    const upstream = 'www.google.com'

    // 代理网站的目录.
    const upstream_path = '/'

    // 手机用户代理网站.
    const upstream_mobile = 'www.google.com'

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

    // 屏蔽 IP 地址.
    const blocked_ip_address = ['0.0.0.0', '127.0.0.1']

    // 源站是否开启 HTTPS.
    const https = true

    // 文本替换.
    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', url.hostname);
    new_request_headers.set('Referer', url.hostname);

    let original_response = await fetch(url.href, {
    method: method,
    headers: new_request_headers
    })

    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;

    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');

    const content_type = new_response_headers.get('content-type');
    if (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;
    }
  7. 返回可重命名,这时就可以直接访问 WorkerName.Subdomain.workers.dev 了:
  8. 觉得域名太长不太好记,可以用自己的域名,前提是要在 cloudflare 解析,选择域名,点击 Workers->Add router
  9. Routesubdomain.yourdomain.com/*Worker 选择前面的部署:
  10. 在域名 DNS 解析里新建一个 CNAME 记录指向 WorkerName.Subdomain.workers.dev,等待生效后就可以用自己的域名访问了:
  11. 有时候会出现下面这个界面,等一会或者换个浏览器再看看: