Skip to content

Instantly share code, notes, and snippets.

@noobnooc
Last active October 3, 2024 11:42
Show Gist options
  • Save noobnooc/d0407b5fb81cff9d36f981170b99d4e6 to your computer and use it in GitHub Desktop.
Save noobnooc/d0407b5fb81cff9d36f981170b99d4e6 to your computer and use it in GitHub Desktop.
cloudflare-worker-proxy
// Website you intended to retrieve for users.
const upstream = 'api.openai.com'
// Custom pathname for the upstream website.
const upstream_path = '/'
// Website you intended to retrieve for users using mobile devices.
const upstream_mobile = upstream
// Countries and regions where you wish to suspend your service.
const blocked_region = []
// 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',
}
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,
body: request.body
})
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;
}
@XxSbyH
Copy link

XxSbyH commented Jul 7, 2023

image

直接复制代码过去的

解决了吗?我也是这样

@AQIU-MAX
Copy link

AQIU-MAX commented Jul 7, 2023

复制过来就这样,上图这样,添加标头了还是一样

@cssjidi
Copy link

cssjidi commented Jul 27, 2023

image

直接复制代码过去的

试试加const或者let去声明

@AndrosEt
Copy link

connection_upgrade 前面加个 var 声明:

var connection_upgrade = new ....

new_response_headers.set('access-control-allow-credentials', true); 这里的 true 要用字符串形式,变成

new_response_headers.set('access-control-allow-credentials', 'true');

@Chapoly1305
Copy link

connection_upgrade 前面加个 var 声明:

var connection_upgrade = new ....

new_response_headers.set('access-control-allow-credentials', true); 这里的 true 要用字符串形式,变成

new_response_headers.set('access-control-allow-credentials', 'true');

感谢更新,确实解决了部分报警,不过控制台仍然对于 clone() 的使用给出了Warning,认为资源浪费。
"Your worker created multiple branches of a single stream (for instance, by calling response.clone() or request.clone()) but did not read the body of both branches. This is wasteful, as it forces the system to buffer the entire stream of data in memory, rather than streaming it through. This may cause your worker to be unexpectedly terminated for going over the memory limit. If you only meant to copy the request or response headers and metadata (e.g. in order to be able to modify them), use the appropriate constructors instead (for instance, new Response(response.body, response), new Request(request), etc)."

以下代码修复了控制台报Warning,我自己进行了一下测试,没有发现异常。供有需要的朋友参考使用。
https://gist.github.com/Chapoly1305/c2f52e198a7cf870d9c0653c1f4d6a5d/revisions

@FreedBird
Copy link

connection_upgrade 前面加个 var 声明:

var connection_upgrade = new ....

new_response_headers.set('access-control-allow-credentials', true); 这里的 true 要用字符串形式,变成

new_response_headers.set('access-control-allow-credentials', 'true');

感谢更新,确实解决了部分报警,不过控制台仍然对于 clone() 的使用给出了Warning,认为资源浪费。 "Your worker created multiple branches of a single stream (for instance, by calling response.clone() or request.clone()) but did not read the body of both branches. This is wasteful, as it forces the system to buffer the entire stream of data in memory, rather than streaming it through. This may cause your worker to be unexpectedly terminated for going over the memory limit. If you only meant to copy the request or response headers and metadata (e.g. in order to be able to modify them), use the appropriate constructors instead (for instance, new Response(response.body, response), new Request(request), etc)."

以下代码修复了控制台报Warning,我自己进行了一下测试,没有发现异常。供有需要的朋友参考使用。 https://gist.github.com/Chapoly1305/c2f52e198a7cf870d9c0653c1f4d6a5d/revisions

非常感谢你,参考了你的js部署一遍就成功了!

@DeSireFire
Copy link

给worker使用自定义域名就会导致访问不到。
报 error 1011.
搞了个简单粗暴的解决方案

const region = request.headers.get('cf-ipcountry').toUpperCase();

改成

const region = 'US'

OK

@amapig
Copy link

amapig commented Feb 10, 2024

image
我上传之后,遇到这个问题,然后浏览器界面总是提示invalid url,请问大家遇到过这个问题吗

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment