🛸 使用代理
众所周知,我们平时访问HTTP,就是直接输入URL外加Query参数或Body参数就开始直接发送请求,随后等待服务端响应便可。请求通过内网或公网一般都可以正常工作(如果客户端和服务端设备正常联通网络的话),就如下图所示:
# 正向代理
但也有很多服务由于网络限制等诸多原因,无法直接访问到。这时候就需要先连接代理服务器,然后再由代理服务器转发请求到您原本要访问的原始服务器。 这种方式,便称为正向代理,过程如下图所示:
当然,正向代理除了能访问原本访问不到的资源这一功能外,还有其它用处:
- 访问原来无法访问的资源,如: Google、油管、企业私有网络服务等
- 做缓存,加速访问速度
- 对客户端访问授权和认证
- 记录用户访问记录(上网行为管理)
除了有正向代理外,自然也有反向代理,但这个概念不在本文档讨论范围,有兴趣可以自行搜索查询相关资料。
# HTTP代理
Forest从1.5.0-RC1
版本开始支持HTTP协议的正向代理,通过声明式的注解即可完成相关任务
使用@HTTPProxy
注解便可以非常简单地为某一个请求方法设置代理,该注解有以下几个属性:
host: 代理服务器主机地址
port: 代理服务器端口号
username: 代理服务验证的用户名
password: 代理服务验证的密码
/**
* 使用 @HTTPProxy 注解设置代理服务器
* host属性为代理服务器主机地址
* port属性为代理服务器端口号
*/
@Post( "http://localhost:8080/hello")
@HTTPProxy(host = "127.0.0.1", port = "10801")
String simplePostWithProxy();
/**
* 使用 @HTTPProxy 注解设置带密码验证的代理服务器
* host属性为代理服务器主机地址
* port属性为代理服务器端口号
* username属性为代理服务验证的用户名
* password属性为代理服务验证的密码
*/
@Post("http://localhost:8080/hello")
@HTTPProxy(host = "127.0.0.1", port = "10801", username = "root", password = "xxxxxx")
String simplePostWithProxyAuth();
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@HTTPProxy
注解也可以设置在接口类上,批量给接口中所有方法设置相同的代理服务器
/**
* 为 PostClient 接口中所有的请发方法设置代理服务器
*/
@BaseRequest(baseURL = "http://localhost:8080")
@HTTPProxy(host = "127.0.0.1", port = "10801")
public interface PostClient {
... ...
}
/**
* 为 PostClientWithProxyAuth 接口中所有的请发方法设置带密码验证的代理服务器
*/
@BaseRequest(baseURL = "http://localhost:8080")
@HTTPProxy(host = "127.0.0.1", port = "10801", username = "root", password = "xxxxxx")
public interface PostClientWithProxyAuth {
... ...
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# Socks代理
Forest 从v1.5.33
版本开始支持 Socks 协议的正向代理,使用方式也基本和 HTTP 代理一致
通过@SocksProxy
注解便可以非常简单地为某一个请求方法设置代理,该注解有以下几个属性:
host: 代理服务器主机地址
port: 代理服务器端口号
username: 代理服务验证的用户名
password: 代理服务验证的密码
/**
* 使用 @SocksProxy 注解设置 Socks 协议代理服务器
* host属性为代理服务器主机地址
* port属性为代理服务器端口号
*/
@Post("http://localhost:8080/hello")
@SocksProxy(host = "127.0.0.1", port = "1089")
String simplePostWithSocksProxy();
/**
* 使用 @SocksProxy 注解设置带密码验证的 Socks 协议代理服务器
* host属性为代理服务器主机地址
* port属性为代理服务器端口号
* username属性为代理服务验证的用户名
* password属性为代理服务验证的密码
*/
@Post(
url = "http://localhost:8080/hello",
data = "username=foo&password=123456"
)
@SocksProxy(host = "127.0.0.1", port = "1089", username = "root", password = "xxxxxx")
String simplePostWithSocksProxyAndAuth();
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@SocksProxy
注解同样也可以设置在接口类上
/**
* 为 PostClient 接口中所有的请发方法设置代理服务器
*/
@BaseRequest(baseURL = "http://localhost:8080")
@SocksProxy(host = "127.0.0.1", port = "10801")
public interface PostClient {
... ...
}
/**
* 为 PostClientWithProxyAuth 接口中所有的请发方法设置带密码验证的代理服务器
*/
@BaseRequest(baseURL = "http://localhost:8080")
@SocksProxy(host = "127.0.0.1", port = "10801", username = "root", password = "xxxxxx")
public interface PostClientWithProxyAuth {
... ...
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@HTTPProxy
注解也可以用于声明 Socks 协议的代理,只要设置 type 属性为ForestProxyType.Socks
/**
* 使用 @HTTPProxy 注解也可以设置 Socks 协议的代理服务器
* type属性为正向代理的协议类型,有 HTTP 和 Socks 两个枚举值
* host属性为代理服务器主机地址
* port属性为代理服务器端口号
*/
@Post( "http://localhost:8080/hello")
@HTTPProxy(type = ForestProxyType.Socks, host = "127.0.0.1", port = "10801")
String simplePostWithProxy();
2
3
4
5
6
7
8
9
# 动态传参
Forest 提供了三种方式来实现动态的代理传参,能够让你在发送请求的那一刻零时决定代理的地址、端口号等参数
动态正向代理传参的三个方式:1. 显示传参;2. 隐式传参;3. 拦截器传参
# 显示传参
使用字符串模板,可以地将全局变量或参数动态传入代理中,也称为(显示)动态正向代理传参
关于如何使用字符串模板以及变量的配置,请参见《模板表达式》
/**
* 使用 @HTTPProxy 注解设置代 HTTP 协议的理服务器
* host 属性值来自全局变量 proxy.host
* port 属性值来自全局变量 proxy.port
* username 属性值来自方法的第一个参数 uname
* password 属性值来自方法的第二个参数 pass
*/
@Post( "http://localhost:8080/hello")
@HTTPProxy(host = "{proxy.host}", port = "{proxy.port}", username="{0}", passowrd="{1}")
String simplePostWithHTTPProxy(String uname, String pass);
/**
* 使用 @SocksProxy 注解设置代 Socks 协议的理服务器
* host 属性值来自全局变量 proxy.host
* port 属性值来自全局变量 proxy.port
* username 属性值来自方法的第一个参数 uname
* password 属性值来自方法的第二个参数 pass
*/
@Post( "http://localhost:8080/hello")
@SocksProxy(host = "{proxy.host}", port = "{proxy.port}", username="{0}", passowrd="{1}")
String simplePostWithSocksProxy(String uname, String pass);
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 隐式传参
如果不想在@HTTPProxy
或@SocksProxy
中显式声明主机地址等信息,并且需要根据请求的各项信息来进行复杂的逻辑判断后才能决定正向代理的具体属性值,那么就可以通过以下方式来实现(隐式)动态正向代理
定义一个类,实现com.dtflys.forest.callback.HTTPProxySource
接口
/**
* 自定义正向代理来源
*/
public class MyHTTPProxySource implements HTTPProxySource {
@Override
public ForestProxy getProxy(ForestRequest req) {
// req 为 Forest 请求对象
String host = "Your Proxy Host"; // 获取代理服务地址
Integer port = ...; // 获取代理服务端口
ForestProxyType type = ...; // HTTP 或 Socks
// ForestProxyType 是一个枚举类,它有两个枚举值:
// ForestProxyType.HTTP: 代表 HTTP 协议的代理类型
// ForestProxyType.Socks: 代表 Socks 协议的代理类型
String username = "Your Proxy Username"; // 代理服务验证的用户名
String password = "Your Proxy Password"; // 代理服务验证的密码
return new ForestProxy(type, host, port)
.username(username)
.password(password);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
通过@HTTPProxy
注解的source
属性配置自定义的正向代理来源
/**
* 使用 @HTTPProxy 注解设置代理服务器
* 它可以可以是 HTTP 协议,也可以是 Socks 协议
* 取决于 MyHTTPProxySource 中返回的 ForestProxy 对象的 type 属性
*/
@Post( "http://localhost:8080/hello")
@HTTPProxy(source = MyHTTPProxySource.class)
String simplePostWithHTTPProxy(String uname, String pass);
2
3
4
5
6
7
8
# 拦截器传参
在拦截器中构建 ForestProxy 对象实例,并赋值给 Forest 请求对象的 proxy 属性
关于如何使用和配置拦截器,请参见《拦截器》
class MyHTTPProxyInterceptor implements Interceptor {
@Override
public boolean beforeExecute(ForestRequest req) {
String host = "Your Proxy Host"; // 获取代理服务地址
Integer port = ...; // 获取代理服务端口
String username = "Your Proxy Username"; // 代理服务验证的用户名
String password = "Your Proxy Password"; // 代理服务验证的密码
// 使用 ForestProxy.http 方法构建基于 HTTP 协议的 Forest 正向代理对象
req.proxy(ForestProxy.http(host, port)
.username(username)
.password(password));
// 或者使用 ForestProxy.socks 方法构建基于 Socks 协议的 Forest 正向代理对象
req.proxy(ForestProxy.socks(host, port)
.username(username)
.password(password));
return true;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24