Serverless-Proxy

由于日常的某些场景需要使用频繁代理,国内代理厂商的代理IP基本都存在各种问题,所以需要自己搭建一个代理服务。
附源码

实现原理

与常规代理不同的是,Serverless-Proxy 是一个无服务器代理,它使用免费的Serverless上部署请求服务(有点儿类似postman)来实现代理功能。因为近些年Serverless的流行,很多厂商都会有免费的可以使用(vercel、netlify),构建多个就可以成为一个代理池。
与常规的代理不同的是,Serverless服务使用域名访问,那怎么实现代理功能呢?就是通过接口服务做中转,将需要代理请求的数据通过接口发送给Serverless服务,Serverless服务再将数据解析后再服务端发送后将响应再写回接口响应中。

食用方法

1
pip install httpx

GET请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import httpx
import json

kwargs = {
"method": "GET",
"url": "http://127.0.0.1:8080/proxy",
"params": {
"method": "GET",
"url": "https://myip.ipip.net",
"headers": json.dumps({"Content-Type": "application/json"})
}
}
res = httpx.request(**kwargs)
if res.status_code == 200:
print(res.text)

POST请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import httpx
import json

kwargs = {
"method": "GET",
"url": "http://127.0.0.1:8080/proxy",
"params": {
"method": "POST",
"url": "https://127.0.0.1:8000",
"data": json.dumps({"test":1}),
"headers": json.dumps({"Content-Type": "application/json"})
}
}
res = httpx.request(**kwargs)
if res.status_code == 200:
print(res.text)

说明

为什么统一使用GET请求? –因为更快

js代码实现

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
const http = require('http');
const urlLib = require('url');

http.createServer((req, res) => {
let obj = urlLib.parse(req.url, true);
let path = obj.pathname;
let query = obj.query;

console.log(path, query);

if (path === '/') {
res.write('Hello World');
res.end();
return;
}


const params = typeof query.params === 'string' ? new URLSearchParams(JSON.parse(query.params)) : query.params;
const url = params ? `${query.url}?${params}` : query.url;
const body = typeof query.body === 'string' ? JSON.parse(query.body) : query.body;
const headers = typeof query.headers === 'string' ? JSON.parse(query.headers) : query.headers;

if (query.method === 'GET') {
fetch(url, {
method: query.method,
headers: headers,
}).then((response) => response.text()).then((text) => {
// console.log(text);
res.write(text);
res.end();
}).catch(err => {
console.log(err);
res.write(text);
res.end();
});
}
if (query.method === 'POST') {
fetch(url, {
method: query.method,
headers: headers,
body: body
}).then((response) => response.text()).then((text) => {
// console.log(text);
res.write(text);
res.end();
}).catch(err => {
console.log(err);
res.write(text);
res.end();
});
}
}).listen(8080);

python代码实现

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
from http.server import HTTPServer, BaseHTTPRequestHandler
from urllib import request, parse


def fetch(**kwargs):
res = "err".encode()
try:
url = kwargs.get("url", "")
if not url: return None
data = parse.urlencode(eval(kwargs["data"])).encode() if kwargs.get("data") else None
req = request.Request(method=kwargs.get("method", "GET"), url=url, data=data,
headers=eval(kwargs["headers"]) if kwargs.get("headers") else None)
res = request.urlopen(req).read()
except Exception as e:
print(f'\033[93m{e}')
return res


class Handler(BaseHTTPRequestHandler):
def do_GET(self):
# print(f'\033[92m{self.path}')
res = "Hello World".encode()
if self.path[1:6] == "proxy":
parsed_url = parse.urlparse(self.path)
params = parse.parse_qs(parsed_url.query)
kwargs = {
"method": "".join(params.get("method", ["GET"])),
"url": "".join(params.get("url", "")),
"params": "".join(params.get("params", {})),
"data": "".join(params.get("data", {})),
"headers": "".join(params.get("headers", "")),
}
print(f'\033[94m{kwargs}')
res = fetch(**kwargs)
self.send_response(200)
self.end_headers()
self.wfile.write(res)


if __name__ == '__main__':
server = HTTPServer(('', 80), Handler)
host, port = server.socket.getsockname()
print(f'\033[92mServing HTTP on (http://{host}:{port})')
server.serve_forever()

__END__