<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-http-proxy</artifactId>
<version>5.0.1</version>
</dependency>
Vert.x HTTP 代理
Vert.x HTTP 代理是一个基于 Vert.x 的反向代理,旨在实现可重用的反向代理逻辑,以专注于更高级的关注点。
此模块具有技术预览状态,这意味着 API 可能会在版本之间发生变化。 |
使用 Vert.x HTTP 代理
要使用 Vert.x HTTP 代理,请将以下依赖项添加到构建描述符的 dependencies 部分
-
Maven(在您的
pom.xml
中)
-
Gradle(在您的
build.gradle
文件中)
dependencies {
compile 'io.vertx:vertx-http-proxy:5.0.1'
}
反向代理服务器
为了使用 Vert.x HTTP 代理实现反向代理,您需要以下内容
-
处理用户代理请求并将其转发到源服务器的代理服务器
-
处理来自代理服务器请求并相应响应的源服务器
您可以创建一个监听端口8080
并实现反向代理逻辑的代理服务器
HttpClient proxyClient = vertx.createHttpClient();
HttpProxy proxy = HttpProxy.reverseProxy(proxyClient);
proxy.origin(7070, "origin");
HttpServer proxyServer = vertx.createHttpServer();
proxyServer.requestHandler(proxy).listen(8080);
所有用户代理请求都会方便地转发到源服务器。
源服务器路由
您可以创建一个代理,将所有流量转发到单个服务器,如前所述。
您可以设置一个源选择器来将流量路由到给定服务器
proxy.origin(OriginRequestProvider.selector(proxyContext -> resolveOriginAddress(proxyContext)));
您可以设置一个函数来创建到源服务器的客户端请求,以获得最大的灵活性
proxy.origin((proxyContext) -> proxyContext.client().request(resolveOriginOptions(proxyContext)));
请求头转发
端到端请求头由代理转发,逐跳请求头被忽略。
请求权威
作为透明代理,请求权威(HTTP/1.1 的 Host
请求头,HTTP/2 的 :authority
伪请求头)被保留。
您可以覆盖请求权威
proxy.addInterceptor(new ProxyInterceptor() {
@Override
public Future<ProxyResponse> handleProxyRequest(ProxyContext context) {
ProxyRequest proxyRequest = context.request();
proxyRequest.setAuthority(HostAndPort.create("example.com", 80));
return ProxyInterceptor.super.handleProxyRequest(context);
}
});
当请求权威被覆盖时,源服务器请求上的 x-forwarded-host
请求头会设置为原始权威值。
更改请求权威可能会产生不良的副作用,并可能影响依赖原始请求权威来处理 Cookie、URL 重定向等的代理 Web 服务器。 |
WebSocket
代理默认支持 WebSocket。
WebSocket 握手请求被转发到源服务器(包括 connection
请求头),握手发生在用户代理和源服务器之间。
您可以使用 setSupportWebSocket
配置 WebSocket 支持。
代理缓存
默认情况下,代理不缓存响应并忽略大多数缓存指令,您可以通过设置缓存选项来启用缓存。
HttpProxy proxy = HttpProxy.reverseProxy(new ProxyOptions().setCacheOptions(new CacheOptions()), proxyClient);
代理拦截
拦截是扩展代理以添加新功能的强大方式。
您可以实现 handleProxyRequest
以对代理请求执行任何操作
proxy.addInterceptor(new ProxyInterceptor() {
@Override
public Future<ProxyResponse> handleProxyRequest(ProxyContext context) {
ProxyRequest proxyRequest = context.request();
filter(proxyRequest.headers());
// Continue the interception chain
return context.sendRequest();
}
});
代理响应也如此
proxy.addInterceptor(new ProxyInterceptor() {
@Override
public Future<Void> handleProxyResponse(ProxyContext context) {
ProxyResponse proxyResponse = context.response();
filter(proxyResponse.headers());
// Continue the interception chain
return context.sendResponse();
}
});
正文过滤
您可以通过简单地将原始 Body
替换为新的来过滤正文
proxy.addInterceptor(new ProxyInterceptor() {
@Override
public Future<Void> handleProxyResponse(ProxyContext context) {
ProxyResponse proxyResponse = context.response();
// Create a filtered body
Body filteredBody = filter(proxyResponse.getBody());
// And then let the response use it
proxyResponse.setBody(filteredBody);
// Continue the interception chain
return context.sendResponse();
}
});
拦截控制
sendRequest
和 sendResponse
继续当前的拦截链,然后将结果发送到源服务器或用户代理。
您可以更改控制,例如,您可以立即向用户代理发送响应,而无需向源服务器发出请求
proxy.addInterceptor(new ProxyInterceptor() {
@Override
public Future<ProxyResponse> handleProxyRequest(ProxyContext context) {
ProxyRequest proxyRequest = context.request();
// Release the underlying resources
proxyRequest.release();
// Create a response and populate it
ProxyResponse proxyResponse = proxyRequest.response()
.setStatusCode(200)
.putHeader("content-type", "text/plain")
.setBody(Body.body(Buffer.buffer("Hello World")));
return Future.succeededFuture(proxyResponse);
}
});
可定制的拦截器
您可以使用 ProxyInterceptor.builder
,它有助于实现一个修改请求/响应头和正文的拦截器
-
请求路径
-
查询参数
-
请求和响应头
-
正文转换
此类拦截器通过 ProxyInterceptorBuilder
创建和配置。
请求头拦截
您可以应用拦截器,通过常用操作更改请求和响应中的请求头
proxy.addInterceptor(
ProxyInterceptor.builder().filteringResponseHeaders(shouldRemove).build());
请求头修改方法可以多次调用,操作将按照配置顺序应用。
请查看 ProxyInterceptorBuilder
获取可用方法的详细信息。
查询参数拦截
您可以应用拦截器来更新或移除查询参数
proxy.addInterceptor(
ProxyInterceptor.builder().settingQueryParam(key, value).build());
查询参数修改方法可以多次调用,操作将按照配置顺序应用。
您也可以参考 ProxyInterceptorBuilder
获取更多信息。
正文拦截器
您可以使用 BodyTransformer
来创建正文转换。
一组预定义转换有助于创建转换器。
BodyTransformer transformer = BodyTransformers.transform(
MediaType.APPLICATION_JSON,
MediaType.APPLICATION_OCTET_STREAM,
buffer -> {
// Apply some transformation
return buffer;
}
);
正文转换器随后通过构建器转换为代理拦截器
proxy.addInterceptor(
ProxyInterceptor
.builder()
.transformingResponseBody(transformer)
.build()
);
BodyTransformers
为常见数据类型(如 JsonObject
)提供转换。
proxy.addInterceptor(
ProxyInterceptor
.builder()
.transformingResponseBody(
BodyTransformers.jsonObject(
jsonObject -> removeSomeFields(jsonObject)
)
).build());
BodyTransformers
中提供的大多数转换是同步的并缓冲字节。默认最大字节量为 256K 字节,您可以提供不同的量
proxy.addInterceptor(
ProxyInterceptor
.builder()
.transformingResponseBody(
BodyTransformers.jsonObject(
// Maximum amount of buffered bytes
128 * 1024,
jsonObject -> removeSomeFields(jsonObject)
)
).build());
请查看 BodyTransformers
以获取其他支持的转换。
您也可以实现 BodyTransformer 契约,以最好地适应您的需求。 |
拦截与 WebSocket 升级
默认情况下,拦截器在 WebSocket 升级期间不会被调用。
要在 WebSocket 握手期间使拦截器可用,请使用 addInterceptor
ProxyInterceptor interceptor = ProxyInterceptor.builder()
.addingPathPrefix("/api")
.build();
proxy.addInterceptor(interceptor, true);