国产chinesehdxxxx野外,国产av无码专区亚洲av琪琪,播放男人添女人下边视频,成人国产精品一区二区免费看,chinese丰满人妻videos

Micronaut HTTP 客戶端過濾器

2023-03-08 15:51 更新

通常,您需要在針對第三方 API 的一組請求中或調(diào)用另一個微服務(wù)時包含相同的 HTTP 標頭或 URL 參數(shù)。

為了簡化這一點,您可以定義應(yīng)用于所有匹配的 HTTP 客戶端請求的 HttpClientFilter 類。

例如,假設(shè)您想要構(gòu)建一個客戶端來與 Bintray REST API 進行通信。為每個 HTTP 調(diào)用指定身份驗證會很乏味。

要解決此問題,您可以定義一個過濾器。下面是一個 BintrayService 的例子:

 Java Groovy  Kotlin 
class BintrayApi {
    public static final String URL = 'https://api.bintray.com'
}

@Singleton
class BintrayService {
    final HttpClient client;
    final String org;

    BintrayService(
            @Client(BintrayApi.URL) HttpClient client,           // (1)
            @Value("${bintray.organization}") String org ) {
        this.client = client;
        this.org = org;
    }

    Flux<HttpResponse<String>> fetchRepositories() {
        return Flux.from(client.exchange(HttpRequest.GET(
                "/repos/" + org), String.class)); // (2)
    }

    Flux<HttpResponse<String>> fetchPackages(String repo) {
        return Flux.from(client.exchange(HttpRequest.GET(
                "/repos/" + org + "/" + repo + "/packages"), String.class)); // (2)
    }
}
class BintrayApi {
    public static final String URL = 'https://api.bintray.com'
}

@Singleton
class BintrayService {
    final HttpClient client
    final String org

    BintrayService(
            @Client(BintrayApi.URL) HttpClient client, // (1)
            @Value('${bintray.organization}') String org ) {
        this.client = client
        this.org = org
    }

    Flux<HttpResponse<String>> fetchRepositories() {
        client.exchange(HttpRequest.GET("/repos/$org"), String) // (2)
    }

    Flux<HttpResponse<String>> fetchPackages(String repo) {
        client.exchange(HttpRequest.GET("/repos/${org}/${repo}/packages"), String) // (2)
    }
}
class BintrayApi {
    public static final String URL = 'https://api.bintray.com'
}

@Singleton
internal class BintrayService(
    @param:Client(BintrayApi.URL) val client: HttpClient, // (1)
    @param:Value("\${bintray.organization}") val org: String) {

    fun fetchRepositories(): Flux<HttpResponse<String>> {
        return Flux.from(client.exchange(HttpRequest.GET<Any>("/repos/$org"), String::class.java)) // (2)
    }

    fun fetchPackages(repo: String): Flux<HttpResponse<String>> {
        return Flux.from(client.exchange(HttpRequest.GET<Any>("/repos/$org/$repo/packages"), String::class.java)) // (2)
    }
}
  1. 為 Bintray API 注入 ReactorHttpClient

  2. 該組織可通過配置進行配置

Bintray API 是安全的。要進行身份驗證,您需要為每個請求添加一個 Authorization 標頭。您可以修改 fetchRepositories 和 fetchPackages 方法以包含每個請求所需的 HTTP 標頭,但使用過濾器要簡單得多:

 Java  Groovy Kotlin 
@Filter("/repos/**") // (1)
class BintrayFilter implements HttpClientFilter {

    final String username;
    final String token;

    BintrayFilter(
            @Value("${bintray.username}") String username, // (2)
            @Value("${bintray.token}") String token ) { // (2)
        this.username = username;
        this.token = token;
    }

    @Override
    public Publisher<? extends HttpResponse<?>> doFilter(MutableHttpRequest<?> request,
                                                         ClientFilterChain chain) {
        return chain.proceed(
                request.basicAuth(username, token) // (3)
        );
    }
}
@Filter('/repos/**') // (1)
class BintrayFilter implements HttpClientFilter {

    final String username
    final String token

    BintrayFilter(
            @Value('${bintray.username}') String username, // (2)
            @Value('${bintray.token}') String token ) { // (2)
        this.username = username
        this.token = token
    }

    @Override
    Publisher<? extends HttpResponse<?>> doFilter(MutableHttpRequest<?> request,
                                                  ClientFilterChain chain) {
        chain.proceed(
                request.basicAuth(username, token) // (3)
        )
    }
}
@Filter("/repos/**") // (1)
internal class BintrayFilter(
        @param:Value("\${bintray.username}") val username: String, // (2)
        @param:Value("\${bintray.token}") val token: String)// (2)
    : HttpClientFilter {

    override fun doFilter(request: MutableHttpRequest<*>, chain: ClientFilterChain): Publisher<out HttpResponse<*>> {
        return chain.proceed(
            request.basicAuth(username, token) // (3)
        )
    }
}
  1. 您只能將部分路徑與客戶端過濾器匹配。

  2. 用戶名和令牌通過配置注入

  3. basicAuth 方法包括 HTTP 基本憑證

現(xiàn)在,當您調(diào)用 bintrayService.fetchRepositories() 方法時,授權(quán) HTTP 標頭包含在請求中。

將另一個客戶端注入 HttpClientFilter

要創(chuàng)建 ReactorHttpClient,Micronaut 需要解析所有 HttpClientFilter 實例,這會在將另一個 ReactorHttpClient 或 @Client bean 注入 HttpClientFilter 實例時創(chuàng)建循環(huán)依賴。

要解決此問題,請使用 BeanProvider 接口將另一個 ReactorHttpClient 或 @Client bean 注入到 HttpClientFilter 的實例中。

以下示例實現(xiàn)了一個允許在 Google Cloud Run 上的服務(wù)之間進行身份驗證的過濾器,演示了如何使用 BeanProvider 注入另一個客戶端:

 Java Groovy  Kotlin 
import io.micronaut.context.BeanProvider;
import io.micronaut.context.annotation.Requires;
import io.micronaut.context.env.Environment;
import io.micronaut.http.HttpRequest;
import io.micronaut.http.HttpResponse;
import io.micronaut.http.MutableHttpRequest;
import io.micronaut.http.annotation.Filter;
import io.micronaut.http.client.HttpClient;
import io.micronaut.http.filter.ClientFilterChain;
import io.micronaut.http.filter.HttpClientFilter;
import org.reactivestreams.Publisher;
import reactor.core.publisher.Mono;

import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URLEncoder;

@Requires(env = Environment.GOOGLE_COMPUTE)
@Filter(patterns = "/google-auth/api/**")
public class GoogleAuthFilter implements HttpClientFilter {

    private final BeanProvider<HttpClient> authClientProvider;

    public GoogleAuthFilter(BeanProvider<HttpClient> httpClientProvider) { // (1)
        this.authClientProvider = httpClientProvider;
    }

    @Override
    public Publisher<? extends HttpResponse<?>> doFilter(MutableHttpRequest<?> request,
                                                         ClientFilterChain chain) {
        return Mono.fromCallable(() -> encodeURI(request))
                .flux()
                .flatMap(uri -> authClientProvider.get().retrieve(HttpRequest.GET(uri) // (2)
                        .header("Metadata-Flavor", "Google")))
                .flatMap(t -> chain.proceed(request.bearerAuth(t)));
    }

    private String encodeURI(MutableHttpRequest<?> request) throws UnsupportedEncodingException {
        URI fullURI = request.getUri();
        String receivingURI = fullURI.getScheme() + "://" + fullURI.getHost();
        return "http://metadata/computeMetadata/v1/instance/service-accounts/default/identity?audience=" +
                URLEncoder.encode(receivingURI, "UTF-8");
    }
}
import io.micronaut.context.annotation.Requires
import io.micronaut.context.env.Environment
import io.micronaut.context.BeanProvider
import io.micronaut.http.HttpResponse
import io.micronaut.http.MutableHttpRequest
import io.micronaut.http.annotation.Filter
import io.micronaut.http.client.HttpClient
import io.micronaut.http.filter.ClientFilterChain
import io.micronaut.http.filter.HttpClientFilter
import org.reactivestreams.Publisher
import reactor.core.publisher.Flux
import reactor.core.publisher.Mono

import static io.micronaut.http.HttpRequest.GET

@Requires(env = Environment.GOOGLE_COMPUTE)
@Filter(patterns = "/google-auth/api/**")
class GoogleAuthFilter implements HttpClientFilter {

    private final BeanProvider<HttpClient> authClientProvider

    GoogleAuthFilter(BeanProvider<HttpClient> httpClientProvider) { // (1)
        this.authClientProvider = httpClientProvider
    }

    @Override
    Publisher<? extends HttpResponse<?>> doFilter(MutableHttpRequest<?> request,
                                                  ClientFilterChain chain) {
        Flux<String> token = Mono.fromCallable(() -> encodeURI(request))
                .flatMap(authURI -> authClientProvider.get().retrieve(GET(authURI).header( // (2)
                        "Metadata-Flavor", "Google"
                )))

        return token.flatMap(t -> chain.proceed(request.bearerAuth(t)))
    }

    private static String encodeURI(MutableHttpRequest<?> request) {
        String receivingURI = "$request.uri.scheme://$request.uri.host"
        "http://metadata/computeMetadata/v1/instance/service-accounts/default/identity?audience=" +
                URLEncoder.encode(receivingURI, "UTF-8")
    }
}
import io.micronaut.context.BeanProvider
import io.micronaut.context.annotation.Requires
import io.micronaut.context.env.Environment
import io.micronaut.http.HttpRequest
import io.micronaut.http.HttpResponse
import io.micronaut.http.MutableHttpRequest
import io.micronaut.http.annotation.Filter
import io.micronaut.http.client.HttpClient
import io.micronaut.http.filter.ClientFilterChain
import io.micronaut.http.filter.HttpClientFilter
import org.reactivestreams.Publisher
import reactor.core.publisher.Mono
import java.net.URLEncoder

@Requires(env = [Environment.GOOGLE_COMPUTE])
@Filter(patterns = ["/google-auth/api/**"])
class GoogleAuthFilter (
    private val authClientProvider: BeanProvider<HttpClient>) : HttpClientFilter { // (1)

    override fun doFilter(request: MutableHttpRequest<*>,
                          chain: ClientFilterChain): Publisher<out HttpResponse<*>?> {
        return Mono.fromCallable { encodeURI(request) }
            .flux()
            .map { authURI: String ->
                authClientProvider.get().retrieve(HttpRequest.GET<Any>(authURI)
                    .header("Metadata-Flavor", "Google") // (2)
                )
            }.flatMap { t -> chain.proceed(request.bearerAuth(t.toString())) }
    }

    private fun encodeURI(request: MutableHttpRequest<*>): String {
        val receivingURI = "${request.uri.scheme}://${request.uri.host}"
        return "http://metadata/computeMetadata/v1/instance/service-accounts/default/identity?audience=" +
                URLEncoder.encode(receivingURI, "UTF-8")
    }

}
  1. BeanProvider 接口用于注入另一個客戶端,避免循環(huán)引用

  2. Provider接口的get()方法用于獲取客戶端實例。

通過注解過濾匹配

對于無論 URL 都應(yīng)將過濾器應(yīng)用于客戶端的情況,可以通過同時應(yīng)用于過濾器和客戶端的注釋來匹配過濾器。給定以下客戶:

 Java Groovy  Kotlin 
import io.micronaut.http.annotation.Get;
import io.micronaut.http.client.annotation.Client;

@BasicAuth // (1)
@Client("/message")
public interface BasicAuthClient {

    @Get
    String getMessage();
}
import io.micronaut.http.annotation.Get
import io.micronaut.http.client.annotation.Client

@BasicAuth // (1)
@Client("/message")
interface BasicAuthClient {

    @Get
    String getMessage()
}
import io.micronaut.http.annotation.Get
import io.micronaut.http.client.annotation.Client

@BasicAuth // (1)
@Client("/message")
interface BasicAuthClient {

    @Get
    fun getMessage(): String
}
  1. @BasicAuth 注解應(yīng)用于客戶端

以下過濾器將過濾客戶端請求:

 Java Groovy  Kotlin 
import io.micronaut.http.HttpResponse;
import io.micronaut.http.MutableHttpRequest;
import io.micronaut.http.filter.ClientFilterChain;
import io.micronaut.http.filter.HttpClientFilter;
import org.reactivestreams.Publisher;

import jakarta.inject.Singleton;

@BasicAuth // (1)
@Singleton // (2)
public class BasicAuthClientFilter implements HttpClientFilter {

    @Override
    public Publisher<? extends HttpResponse<?>> doFilter(MutableHttpRequest<?> request,
                                                         ClientFilterChain chain) {
        return chain.proceed(request.basicAuth("user", "pass"));
    }
}
import io.micronaut.http.HttpResponse
import io.micronaut.http.MutableHttpRequest
import io.micronaut.http.filter.ClientFilterChain
import io.micronaut.http.filter.HttpClientFilter
import org.reactivestreams.Publisher

import jakarta.inject.Singleton

@BasicAuth // (1)
@Singleton // (2)
class BasicAuthClientFilter implements HttpClientFilter {

    @Override
    Publisher<? extends HttpResponse<?>> doFilter(MutableHttpRequest<?> request,
                                                  ClientFilterChain chain) {
        chain.proceed(request.basicAuth("user", "pass"))
    }
}
import io.micronaut.http.HttpResponse
import io.micronaut.http.MutableHttpRequest
import io.micronaut.http.filter.ClientFilterChain
import io.micronaut.http.filter.HttpClientFilter
import org.reactivestreams.Publisher

import jakarta.inject.Singleton

@BasicAuth // (1)
@Singleton // (2)
class BasicAuthClientFilter : HttpClientFilter {

    override fun doFilter(request: MutableHttpRequest<*>,
                          chain: ClientFilterChain): Publisher<out HttpResponse<*>> {
        return chain.proceed(request.basicAuth("user", "pass"))
    }
}
  1. 相同的注釋 @BasicAuth 應(yīng)用于過濾器

  2. 通常 @Filter 注釋默認使過濾器成為單例。因為沒有使用@Filter 注解,所以必須應(yīng)用所需的范圍

@BasicAuth 注釋只是一個示例,可以替換為您自己的注釋。

 Java Groovy  Kotlin 
import io.micronaut.http.annotation.FilterMatcher;

import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

@FilterMatcher // (1)
@Documented
@Retention(RUNTIME)
@Target({TYPE, PARAMETER})
public @interface BasicAuth {
}
import io.micronaut.http.annotation.FilterMatcher

import java.lang.annotation.Documented
import java.lang.annotation.Retention
import java.lang.annotation.Target

import static java.lang.annotation.ElementType.PARAMETER
import static java.lang.annotation.ElementType.TYPE
import static java.lang.annotation.RetentionPolicy.RUNTIME

@FilterMatcher // (1)
@Documented
@Retention(RUNTIME)
@Target([TYPE, PARAMETER])
@interface BasicAuth {
}
import io.micronaut.http.annotation.FilterMatcher
import kotlin.annotation.AnnotationRetention.RUNTIME
import kotlin.annotation.AnnotationTarget.CLASS
import kotlin.annotation.AnnotationTarget.VALUE_PARAMETER

@FilterMatcher // (1)
@MustBeDocumented
@Retention(RUNTIME)
@Target(CLASS, VALUE_PARAMETER)
annotation class BasicAuth
  1. 自定義注釋的唯一要求是必須存在@FilterMatcher 注釋


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號