CloudFlare是国外一家知名的cdn服务商,Workers-Proxy是基于Cloudflare Workers的轻量级Javascript 反向代理。 用户可以在Cloudflare的全球网络上部署反向代理,而无需设置虚拟专用服务器和配置Nginx或Apache。

通过配置地区和 IP 过滤器,你可以根据法律规定在部分国家和地区停用反向代理服务。借助移动端跳转工具,你可以根据用户的设备来分发不同的网站。

 

Workers特点:

1、建立镜像网站

2、利用Cloudflare的全球网络提高加载速度

3、提高安全性(隐藏网站的IP地址)阻止特定区域或IP地址

4、将移动用户重定向到其他网页

创建就很简单了,就不介绍了,这里分享2个版本的Workers反代代码。

第一个:

  1. // 替换成你想镜像的站点
  2. const upstream = ‘www.google.com’
  3. // 如果那个站点有专门的移动适配站点,否则保持和上面一致
  4. const upstream_mobile = ‘www.google.com’
  5. // 你希望禁止哪些国家访问
  6. const blocked_region = [‘RU’]
  7. // 禁止自访问
  8. const blocked_ip_address = [‘0.0.0.0’, ‘127.0.0.1’]
  9. // 替换成你想镜像的站点
  10. const replace_dict = {
  11. ‘$upstream’: ‘$custom_domain’,
  12. ‘//www.google.com’:
  13. }
  14. //以下内容都不用动
  15. addEventListener(‘fetch’, event => {
  16. event.respondWith(fetchAndApply(event.request));
  17. })
  18. async function fetchAndApply(request) {
  19. const region = request.headers.get(‘cf-ipcountry’).toUpperCase();
  20. const ip_address = request.headers.get(‘cf-connecting-ip’);
  21. const user_agent = request.headers.get(‘user-agent’);
  22. let response = null;
  23. let url = new URL(request.url);
  24. let url_host = url.host;
  25. if (url.protocol == ‘http:’) {
  26. url.protocol = ‘https:’
  27. response = Response.redirect(url.href);
  28. return response;
  29. }
  30. if (await device_status(user_agent)) {
  31. upstream_domain = upstream
  32. } else {
  33. upstream_domain = upstream_mobile
  34. }
  35. url.host = upstream_domain;
  36. if (blocked_region.includes(region)) {
  37. response = new Response(‘Access denied: WorkersProxy is not available in your region yet.’, {
  38. status: 403
  39. });
  40. } else if(blocked_ip_address.includes(ip_address)){
  41. response = new Response(‘Access denied: Your IP address is blocked by WorkersProxy.’, {
  42. status: 403
  43. });
  44. } else{
  45. let method = request.method;
  46. let request_headers = request.headers;
  47. let new_request_headers = new Headers(request_headers);
  48. new_request_headers.set(‘Host’, upstream_domain);
  49. new_request_headers.set(‘Referer’, url.href);
  50. let original_response = await fetch(url.href, {
  51. method: method,
  52. headers: new_request_headers
  53. })
  54. let original_response_clone = original_response.clone();
  55. let original_text = null;
  56. let response_headers = original_response.headers;
  57. let new_response_headers = new Headers(response_headers);
  58. let status = original_response.status;
  59. new_response_headers.set(‘access-control-allow-origin’, ‘*’);
  60. new_response_headers.set(‘access-control-allow-credentials’, true);
  61. new_response_headers.delete(‘content-security-policy’);
  62. new_response_headers.delete(‘content-security-policy-report-only’);
  63. new_response_headers.delete(‘clear-site-data’);
  64. const content_type = new_response_headers.get(‘content-type’);
  65. if (content_type.includes(‘text/html’) && content_type.includes(‘UTF-8’)) {
  66. original_text = await replace_response_text(original_response_clone, upstream_domain, url_host);
  67. } else {
  68. original_text = original_response_clone.body
  69. }
  70. response = new Response(original_text, {
  71. status,
  72. headers: new_response_headers
  73. })
  74. }
  75. return response;
  76. }
  77. async function replace_response_text(response, upstream_domain, host_name) {
  78. let text = await response.text()
  79. var i, j;
  80. for (i in replace_dict) {
  81. j = replace_dict[i]
  82. if (i == ‘$upstream’) {
  83. i = upstream_domain
  84. } else if (i == ‘$custom_domain’) {
  85. i = host_name
  86. }
  87. if (j == ‘$upstream’) {
  88. j = upstream_domain
  89. } else if (j == ‘$custom_domain’) {
  90. j = host_name
  91. }
  92. let re = new RegExp(i, ‘g’)
  93. text = text.replace(re, j);
  94. }
  95. return text;
  96. }
  97. async function device_status (user_agent_info) {
  98. var agents = [“Android”, “iPhone”, “SymbianOS”, “Windows Phone”, “iPad”, “iPod”];
  99. var flag = true;
  100. for (var v = 0; v < agents.length; v++) { if (user_agent_info.indexOf(agents[v]) > 0) {
  101. flag = false;
  102. break;
  103. }
  104. }
  105. return flag;
  106. }

第二个:

  1. // 替换成你想镜像的站点
  2. const upstream = ‘google.com’
  3. // 如果那个站点有专门的移动适配站点,否则保持和上面一致
  4. const upstream_mobile = ‘m.google.com’
  5. // 密码访问
  6. const openAuth = false
  7. const username = ‘username’
  8. const password = ‘password’
  9. // 你希望禁止哪些国家访问
  10. const blocked_region = [‘RU’]
  11. // 禁止自访问
  12. const blocked_ip_address = [‘0.0.0.0’, ‘127.0.0.1’]
  13. // 替换成你想镜像的站点
  14. const replace_dict = {
  15. ‘$upstream’: ‘$custom_domain’,
  16. ‘//google.com’:
  17. }
  18. function unauthorized() {
  19. return new Response(‘Unauthorized’, {
  20. headers: {
  21. ‘WWW-Authenticate’: ‘Basic realm=”goindex”‘,
  22. ‘Access-Control-Allow-Origin’: ‘*’
  23. },
  24. status: 401
  25. });
  26. }
  27. function parseBasicAuth(auth) {
  28. try {
  29. return atob(auth.split(‘ ‘).pop()).split(‘:’);
  30. } catch (e) {
  31. return [];
  32. }
  33. }
  34. function doBasicAuth(request) {
  35. const auth = request.headers.get(‘Authorization’);
  36. if (!auth || !/^Basic [A-Za-z0-9._~+/-]+=*$/i.test(auth)) {
  37. return false;
  38. }
  39. const [user, pass] = parseBasicAuth(auth);
  40. return user === username && pass === password;
  41. }
  42. async function fetchAndApply(request) {
  43. if (request.method === ‘OPTIONS’) // allow preflight request
  44. return new Response(, {
  45. status: 200,
  46. headers: {
  47. ‘Access-Control-Allow-Origin’: ‘*’,
  48. ‘Access-Control-Allow-Headers’: ‘*’,
  49. ‘Access-Control-Allow-Methods’: ‘GET, POST, PUT, HEAD, OPTIONS’
  50. }
  51. });
  52. if (openAuth && !doBasicAuth(request)) {
  53. return unauthorized();
  54. }
  55. const region = request.headers.get(‘cf-ipcountry’).toUpperCase();
  56. const ip_address = request.headers.get(‘cf-connecting-ip’);
  57. const user_agent = request.headers.get(‘user-agent’);
  58. let response = null;
  59. let url = new URL(request.url);
  60. let url_host = url.host;
  61. if (url.protocol == ‘http:’) {
  62. url.protocol = ‘https:’
  63. response = Response.redirect(url.href);
  64. return response;
  65. }
  66. if (await device_status(user_agent)) {
  67. upstream_domain = upstream
  68. } else {
  69. upstream_domain = upstream_mobile
  70. }
  71. url.host = upstream_domain;
  72. if (blocked_region.includes(region)) {
  73. response = new Response(‘Access denied: WorkersProxy is not available in your region yet.’, {
  74. status: 403
  75. });
  76. } else if(blocked_ip_address.includes(ip_address)){
  77. response = new Response(‘Access denied: Your IP address is blocked by WorkersProxy.’, {
  78. status: 403
  79. });
  80. } else{
  81. let method = request.method;
  82. let request_headers = request.headers;
  83. let new_request_headers = new Headers(request_headers);
  84. new_request_headers.set(‘Host’, upstream_domain);
  85. new_request_headers.set(‘Referer’, url.href);
  86. let original_response = await fetch(url.href, {
  87. method: method,
  88. headers: new_request_headers
  89. })
  90. let original_response_clone = original_response.clone();
  91. let original_text = null;
  92. let response_headers = original_response.headers;
  93. let new_response_headers = new Headers(response_headers);
  94. let status = original_response.status;
  95. new_response_headers.set(‘access-control-allow-origin’, ‘*’);
  96. new_response_headers.set(‘access-control-allow-credentials’, true);
  97. new_response_headers.delete(‘content-security-policy’);
  98. new_response_headers.delete(‘content-security-policy-report-only’);
  99. new_response_headers.delete(‘clear-site-data’);
  100. const content_type = new_response_headers.get(‘content-type’);
  101. if (content_type.includes(‘text/html’) && content_type.includes(‘UTF-8’)) {
  102. original_text = await replace_response_text(original_response_clone, upstream_domain, url_host);
  103. } else {
  104. original_text = original_response_clone.body
  105. }
  106. response = new Response(original_text, {
  107. status,
  108. headers: new_response_headers
  109. })
  110. }
  111. return response;
  112. }
  113. addEventListener(‘fetch’, event => {
  114. event.respondWith(fetchAndApply(event.request).catch(err => {
  115. console.error(err);
  116. new Response(JSON.stringify(err.stack), {
  117. status: 500,
  118. headers: {
  119. ‘Content-Type’: ‘application/json’
  120. }
  121. });
  122. }));
  123. })
  124. async function replace_response_text(response, upstream_domain, host_name) {
  125. let text = await response.text()
  126. var i, j;
  127. for (i in replace_dict) {
  128. j = replace_dict[i]
  129. if (i == ‘$upstream’) {
  130. i = upstream_domain
  131. } else if (i == ‘$custom_domain’) {
  132. i = host_name
  133. }
  134. if (j == ‘$upstream’) {
  135. j = upstream_domain
  136. } else if (j == ‘$custom_domain’) {
  137. j = host_name
  138. }
  139. let re = new RegExp(i, ‘g’)
  140. text = text.replace(re, j);
  141. }
  142. return text;
  143. }
  144. async function device_status (user_agent_info) {
  145. var agents = [“Android”, “iPhone”, “SymbianOS”, “Windows Phone”, “iPad”, “iPod”];
  146. var flag = true;
  147. for (var v = 0; v < agents.length; v++) { if (user_agent_info.indexOf(agents[v]) > 0) {
  148. flag = false;
  149. break;
  150. }
  151. }
  152. return flag;
  153. }
  154.