阅读(4255) (0)

Micronaut 使用 ProxyHttpClient 代理请求

2023-02-23 13:36:28 更新

微服务环境中的一个常见需求是将网关微服务中的请求代理到其他后端微服务。

常规的 HttpClient API 是围绕简化消息交换而设计的,而不是为代理请求而设计的。对于这种情况,请使用 ProxyHttpClient,它可用于从 HTTP 服务器过滤器到后端微服务的代理请求。

以下示例演示了将 URI /proxy 下的请求重写到同一服务器上的 URI /real(尽管在真实环境中您通常代理到另一台服务器):

重写原始请求的代理过滤器

 Java Groovy  Kotlin 
import io.micronaut.core.async.publisher.Publishers;
import io.micronaut.core.util.StringUtils;
import io.micronaut.http.HttpRequest;
import io.micronaut.http.MutableHttpResponse;
import io.micronaut.http.annotation.Filter;
import io.micronaut.http.client.ProxyHttpClient;
import io.micronaut.http.filter.HttpServerFilter;
import io.micronaut.http.filter.ServerFilterChain;
import io.micronaut.runtime.server.EmbeddedServer;
import org.reactivestreams.Publisher;

@Filter("/proxy/**")
public class ProxyFilter implements HttpServerFilter { // (1)

    private final ProxyHttpClient client;
    private final EmbeddedServer embeddedServer;

    public ProxyFilter(ProxyHttpClient client,
                       EmbeddedServer embeddedServer) { // (2)
        this.client = client;
        this.embeddedServer = embeddedServer;
    }

    @Override
    public Publisher<MutableHttpResponse<?>> doFilter(HttpRequest<?> request,
                                                      ServerFilterChain chain) {
        return Publishers.map(client.proxy( // (3)
                request.mutate() // (4)
                        .uri(b -> b // (5)
                                .scheme("http")
                                .host(embeddedServer.getHost())
                                .port(embeddedServer.getPort())
                                .replacePath(StringUtils.prependUri(
                                        "/real",
                                        request.getPath().substring("/proxy".length())
                                ))
                        )
                        .header("X-My-Request-Header", "XXX") // (6)
        ), response -> response.header("X-My-Response-Header", "YYY"));
    }
}
import io.micronaut.core.async.publisher.Publishers
import io.micronaut.core.util.StringUtils
import io.micronaut.http.HttpRequest
import io.micronaut.http.MutableHttpResponse
import io.micronaut.http.annotation.Filter
import io.micronaut.http.client.ProxyHttpClient
import io.micronaut.http.filter.HttpServerFilter
import io.micronaut.http.filter.ServerFilterChain
import io.micronaut.http.uri.UriBuilder
import io.micronaut.runtime.server.EmbeddedServer
import org.reactivestreams.Publisher

@Filter("/proxy/**")
class ProxyFilter implements HttpServerFilter { // (1)

    private final ProxyHttpClient client
    private final EmbeddedServer embeddedServer

    ProxyFilter(ProxyHttpClient client,
                EmbeddedServer embeddedServer) { // (2)
        this.client = client
        this.embeddedServer = embeddedServer
    }

    @Override
    Publisher<MutableHttpResponse<?>> doFilter(HttpRequest<?> request,
                                               ServerFilterChain chain) {
        Publishers.map(client.proxy( // (3)
                request.mutate() // (4)
                        .uri { UriBuilder b -> // (5)
                            b.with {
                                scheme("http")
                                host(embeddedServer.host)
                                port(embeddedServer.port)
                                replacePath(StringUtils.prependUri(
                                        "/real",
                                        request.path.substring("/proxy".length())
                                ))
                            }
                        }
                        .header("X-My-Request-Header", "XXX") // (6)
        ), { it.header("X-My-Response-Header", "YYY") })
    }
}
import io.micronaut.core.async.publisher.Publishers
import io.micronaut.core.util.StringUtils
import io.micronaut.http.HttpRequest
import io.micronaut.http.MutableHttpResponse
import io.micronaut.http.annotation.Filter
import io.micronaut.http.client.ProxyHttpClient
import io.micronaut.http.filter.HttpServerFilter
import io.micronaut.http.filter.ServerFilterChain
import io.micronaut.http.uri.UriBuilder
import io.micronaut.runtime.server.EmbeddedServer
import org.reactivestreams.Publisher

@Filter("/proxy/**")
class ProxyFilter(
    private val client: ProxyHttpClient, // (2)
    private val embeddedServer: EmbeddedServer
) : HttpServerFilter { // (1)

    override fun doFilter(request: HttpRequest<*>,
                          chain: ServerFilterChain): Publisher<MutableHttpResponse<*>> {
        return Publishers.map(client.proxy( // (3)
            request.mutate() // (4)
                .uri { b: UriBuilder -> // (5)
                    b.apply {
                        scheme("http")
                        host(embeddedServer.host)
                        port(embeddedServer.port)
                        replacePath(StringUtils.prependUri(
                            "/real",
                            request.path.substring("/proxy".length))
                        )
                    }
                }
                .header("X-My-Request-Header", "XXX") // (6)
        ), { response: MutableHttpResponse<*> -> response.header("X-My-Response-Header", "YYY") })
    }
}
  1. 过滤器扩展了 HttpServerFilter

  2. ProxyHttpClient 被注入到构造函数中。

  3. 代理方法代理请求

  4. 请求发生变化以修改 URI 并包含一个额外的标头

  5. UriBuilder API 重写 URI

  6. 包括额外的请求和响应标头

ProxyHttpClient API 是一个低级 API,可用于构建更高级别的抽象,例如 API 网关。