网络代理的原理
相信对于各位程序员👨🏻💻来说梯子
是少不了的,但是你有了解过梯子
是怎么运作的吗,在代码中又如何使用梯子
呢?最近在本地调试ChatGPT
的接口时需要频繁使用代理索性来看一下代理的运作方式。
网络代理软件的原理
基本原理
一个网络代理软件首先要在本地的电脑或者其他设备有一个客户端proxy client
,其次还需要在远程服务器(通常是海外)部署一个服务端proxy server
,client
和server
之间的通信需要经过加密。我们平时听到的Sock5
协议实际上是图中红圈圈住的部分,即浏览器和proxy client
之间用的,该协议的作用是运行浏览器告诉proxy server
自己要访问哪个地方
全局视角
- Proxy Client:代理客户端
- xx协议端口:客户端会监听多个端口,每个端口对应一种代理协议,浏览器根据设定好的代理协议访问指定的端口
- xx协议协议栈:客户端接收到浏览器访问后会调用对应的协议栈处理,比如
Sock5
协议栈就会和浏览器执行一次握手+认证后再做代理工作 - Tunnels:代理隧道,当协议栈需要访问代理服务器(
proxy server
)时,会选择一条代理隧道作为通道,通过该隧道和代理服务器交换数据,数据的加密工作就是在这里完成的。代理隧道可以为多条或者一条,本地的请求将复用这些代理隧道,请求的响应通过id
区分,比如当隧道只有一条时,本地电脑的Chrome
和Safari
的请求数据都会走这一条隧道,但是各自的请求/响应数据包都会打上id
,代理客户端会根据数据包的id
将数据派发给对应的浏览器。
- Proxy Server:代理服务端
- Tunnel事件处理中心:代理服务器在收到来自代理客户端的数据包后,会解析数据包并执行其中包含的指令,比如
建立和Google.com的连接
- duplex handler:代理服务器与目标服务器之间的双工通信,负责:
- 收到代理客户端发过来的数据后向目标服务器写
- 收到目标服务器的数据后向代理客户端写
- Tunnel事件处理中心:代理服务器在收到来自代理客户端的数据包后,会解析数据包并执行其中包含的指令,比如
如何在代码中使用
我们如果要在代码中调用需要代理的接口(比如调用爆火的ChatGPT),如果你不用梯子
那只能通过代码中设置代理到海外才行,如果你本地有梯子
多数情况下在代码中不生效,除非开全局代理,全局代理会导致使用国内的软件巨卡(发个微信都转圈圈🙄)。
这时候最好的办法就是在代码里需要用代理的地方手动设置,这样还有个好处就是可以有多个代理 在代码中轮询(可以避免基于IP的限流。。)
以OKHTTP为例调用Google的接口:
public static void proxyTest() {
// 创建代理服务器
Proxy proxy = new Proxy(Proxy.Type.SOCKS, new InetSocketAddress("127.0.0.1", 15733));
// 创建 OkHttpClient 实例,并设置代理
OkHttpClient client = new OkHttpClient.Builder()
.proxy(proxy)
.build();
MediaType mediaType = MediaType.parse("application/x-www-form-urlencoded");
RequestBody body = RequestBody.create(mediaType, "q=macaoyuan");
Request request = new Request.Builder()
.url("https://google-translate1.p.rapidapi.com/language/translate/v2/detect")
.post(body)
.build();
try {
Response response = client.newCall(request).execute();
assert response.body() != null;
System.out.println(response.body().string());
} catch (IOException e) {
System.out.println("An error occurred: " + e.getMessage());
}
}
响应:
{
"message": "Invalid API key."
}
可以看到成功响应了结果,这个报错是因为没有Google接口的API key
但是我们只要证明网络是连通的即可。