Lxn-Chan!

(~ ̄▽ ̄)→))* ̄▽ ̄*)o

使用 Cloudflare 做代理转发国内无法到达的请求

写在前面

  • 请绝对不要使用这项或类似技术去做违法的事情

  • 本站不提供任何演示站或提供对外服务。

JSProxy

主要用途是查看网页,但是打不开一些需要登录(Twitter)以及有强抗 Spam (Google)的网页。

设置 gh-pages

首先打开 Github , Fork jsproxy 仓库到自己的账号下。

Fork 完成后,打开自己账号下该仓库的Setting,左侧Pages,在Source中选择gh-pages,然后点Save保存,刷新后会出现Your site is published at字样,将后面的地址直接复制到浏览器打开,若能正常显示页面则部署成功。

设置 Cloudflare

新建一个 Workers ,创建好后再快速编辑页面输入如下代码:

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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
'use strict'

/**
* static files (404.html, sw.js, conf.js)
*/
const ASSET_URL = 'https://xxx.github.io/jsproxy/' //这里填写你Github pages的网址!

const JS_VER = 10
const MAX_RETRY = 1

/** @type {RequestInit} */
const PREFLIGHT_INIT = {
status: 204,
headers: new Headers({
'access-control-allow-origin': '*',
'access-control-allow-methods': 'GET,POST,PUT,PATCH,TRACE,DELETE,HEAD,OPTIONS',
'access-control-max-age': '1728000',
}),
}

/**
* @param {any} body
* @param {number} status
* @param {Object<string, string>} headers
*/
function makeRes(body, status = 200, headers = {}) {
headers['--ver'] = JS_VER
headers['access-control-allow-origin'] = '*'
return new Response(body, {status, headers})
}


/**
* @param {string} urlStr
*/
function newUrl(urlStr) {
try {
return new URL(urlStr)
} catch (err) {
return null
}
}


addEventListener('fetch', e => {
const ret = fetchHandler(e)
.catch(err => makeRes('cfworker error:\n' + err.stack, 502))
e.respondWith(ret)
})


/**
* @param {FetchEvent} e
*/
async function fetchHandler(e) {
const req = e.request
const urlStr = req.url
const urlObj = new URL(urlStr)
const path = urlObj.href.substr(urlObj.origin.length)

if (urlObj.protocol === 'http:') {
urlObj.protocol = 'https:'
return makeRes('', 301, {
'strict-transport-security': 'max-age=99999999; includeSubDomains; preload',
'location': urlObj.href,
})
}

if (path.startsWith('/http/')) {
return httpHandler(req, path.substr(6))
}

switch (path) {
case '/http':
return makeRes('请更新 cfworker 到最新版本!')
case '/ws':
return makeRes('not support', 400)
case '/works':
return makeRes('it works')
default:
// static files
return fetch(ASSET_URL + path)
}
}


/**
* @param {Request} req
* @param {string} pathname
*/
function httpHandler(req, pathname) {
const reqHdrRaw = req.headers
if (reqHdrRaw.has('x-jsproxy')) {
return Response.error()
}

// preflight
if (req.method === 'OPTIONS' &&
reqHdrRaw.has('access-control-request-headers')
) {
return new Response(null, PREFLIGHT_INIT)
}

let acehOld = false
let rawSvr = ''
let rawLen = ''
let rawEtag = ''

const reqHdrNew = new Headers(reqHdrRaw)
reqHdrNew.set('x-jsproxy', '1')

// 此处逻辑和 http-dec-req-hdr.lua 大致相同
// https://github.com/EtherDream/jsproxy/blob/master/lua/http-dec-req-hdr.lua
const refer = reqHdrNew.get('referer')
const query = refer.substr(refer.indexOf('?') + 1)
if (!query) {
return makeRes('missing params', 403)
}
const param = new URLSearchParams(query)

for (const [k, v] of Object.entries(param)) {
if (k.substr(0, 2) === '--') {
// 系统信息
switch (k.substr(2)) {
case 'aceh':
acehOld = true
break
case 'raw-info':
[rawSvr, rawLen, rawEtag] = v.split('|')
break
}
} else {
// 还原 HTTP 请求头
if (v) {
reqHdrNew.set(k, v)
} else {
reqHdrNew.delete(k)
}
}
}
if (!param.has('referer')) {
reqHdrNew.delete('referer')
}

// cfworker 会把路径中的 `//` 合并成 `/`
const urlStr = pathname.replace(/^(https?):\/+/, '$1://')
const urlObj = newUrl(urlStr)
if (!urlObj) {
return makeRes('invalid proxy url: ' + urlStr, 403)
}

/** @type {RequestInit} */
const reqInit = {
method: req.method,
headers: reqHdrNew,
redirect: 'manual',
}
if (req.method === 'POST') {
reqInit.body = req.body
}
return proxy(urlObj, reqInit, acehOld, rawLen, 0)
}


/**
*
* @param {URL} urlObj
* @param {RequestInit} reqInit
* @param {number} retryTimes
*/
async function proxy(urlObj, reqInit, acehOld, rawLen, retryTimes) {
const res = await fetch(urlObj.href, reqInit)
const resHdrOld = res.headers
const resHdrNew = new Headers(resHdrOld)

let expose = '*'

for (const [k, v] of resHdrOld.entries()) {
if (k === 'access-control-allow-origin' ||
k === 'access-control-expose-headers' ||
k === 'location' ||
k === 'set-cookie'
) {
const x = '--' + k
resHdrNew.set(x, v)
if (acehOld) {
expose = expose + ',' + x
}
resHdrNew.delete(k)
}
else if (acehOld &&
k !== 'cache-control' &&
k !== 'content-language' &&
k !== 'content-type' &&
k !== 'expires' &&
k !== 'last-modified' &&
k !== 'pragma'
) {
expose = expose + ',' + k
}
}

if (acehOld) {
expose = expose + ',--s'
resHdrNew.set('--t', '1')
}

// verify
if (rawLen) {
const newLen = resHdrOld.get('content-length') || ''
const badLen = (rawLen !== newLen)

if (badLen) {
if (retryTimes < MAX_RETRY) {
urlObj = await parseYtVideoRedir(urlObj, newLen, res)
if (urlObj) {
return proxy(urlObj, reqInit, acehOld, rawLen, retryTimes + 1)
}
}
return makeRes(res.body, 400, {
'--error': `bad len: ${newLen}, except: ${rawLen}`,
'access-control-expose-headers': '--error',
})
}

if (retryTimes > 1) {
resHdrNew.set('--retry', retryTimes)
}
}

let status = res.status

resHdrNew.set('access-control-expose-headers', expose)
resHdrNew.set('access-control-allow-origin', '*')
resHdrNew.set('--s', status)
resHdrNew.set('--ver', JS_VER)

resHdrNew.delete('content-security-policy')
resHdrNew.delete('content-security-policy-report-only')
resHdrNew.delete('clear-site-data')

if (status === 301 ||
status === 302 ||
status === 303 ||
status === 307 ||
status === 308
) {
status = status + 10
}

return new Response(res.body, {
status,
headers: resHdrNew,
})
}


/**
* @param {URL} urlObj
*/
function isYtUrl(urlObj) {
return (
urlObj.host.endsWith('.googlevideo.com') &&
urlObj.pathname.startsWith('/videoplayback')
)
}

/**
* @param {URL} urlObj
* @param {number} newLen
* @param {Response} res
*/
async function parseYtVideoRedir(urlObj, newLen, res) {
if (newLen > 2000) {
return null
}
if (!isYtUrl(urlObj)) {
return null
}
try {
const data = await res.text()
urlObj = new URL(data)
} catch (err) {
return null
}
if (!isYtUrl(urlObj)) {
return null
}
return urlObj
}

输入完成后点击“保存并部署”即可使用,访问地址即为“路由”字段下带.workers.dev字样的域名。

cloudflare-cors-anywhere

cloudflare-cors-anywhere 用于代理 CORS 请求,可用于代理 API 等。

部署

打开 cloudflare-cors-anywhere 仓库,然后把index.js中的内容整体复制到 Cloudflare Workers 内即可。

使用

访问“路由”字段下带.workers.dev字样的域名,若部署正确会返回一些有关 Cloudflare 节点和本机网络相关的信息;使用方法为域名+/?+欲代理域名。

示例:

1
https://myproxy.myqcloud.workers.dev/?https://www.googleapis.com/auth/documents.readonly

 简单说两句



联系站长 | 安装证书 | 友情链接

备案号:辽ICP备19013963号

中国互联网违法和不良信息举报中心

架构版本号:8.0.7 | 本站已全面支持IPv6

本站由又拍云提供CDN加速服务和存储服务

正在载入运行数据(1/2)请稍后...
正在载入运行数据(2/2)请稍后...

Copyright 2022 LingXuanNing, All rights reserved.