在Spring Cloud Gateway中通过service-name同步调用微服务

wnvonmuf  于 5个月前  发布在  Spring
关注(0)|答案(1)|浏览(67)

我有一个云API网关相关的实现参考this构建。
在那里,我通过AuthenticationFilter调用该网关内的身份验证服务。

  • 云网关-服务:7130
  • 咨询服务:9898
  • 联系电话:0712 - 8888888
    application.yml
server:
  port: 7130
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8083/eureka
spring:
  application:
    name: CLOUD-GATEWAY-SERVICE
  cloud:
    gateway:
      routes:
      - id: mtoken-exchange-service
        uri: lb://EXCHANGE-SERVICE
        predicates:
        - Path=/employee/**
        filters:
          - name: AuthenticationFilter
            args:
              role: ROLE_ADMIN
      - id: mtokens-authentication-service
        uri: lb://AUTHENTICATION-SERVICE
        predicates:
          - Path=/auth/**

字符串

  • Sping Boot 版本:3.1.1
  • Spring Cloud版本:2022.0.3
  • Java版本:17

目前,我使用RestTemplate来实现这一点;但我也尝试了Feign和Webclient。
当我使用下面提到的主机和端口访问时,它可以工作。(这里我使用它而没有@LoadBalanced注解)

template.getForObject("http://localhost:7130/auth/validate?token=<Bearer_Token>&role=ROLE_ADMIN", Boolean.class);
template.getForObject("http://localhost:9898/auth/validate?token=<Bearer_Token>&role=ROLE_ADMIN", Boolean.class);


但是,当我尝试使用下面提到的服务名称访问时,它会因未知主机异常而失败。

template.getForObject("http://CLOUD-GATEWAY-SERVICE/auth/validate?token=<Bearer_Token>&role=ROLE_ADMIN", Boolean.class);
template.getForObject("http://AUTHENTICATION-SERVICE/auth/validate?token=<Bearer_Token>&role=ROLE_ADMIN", Boolean.class);


然后,正如在这篇[https://stackoverflow.com/questions/37159662/microservices-resttemplate-unknownessexception]文章中提到的,我用@LoadBalanced注解了RestTemplate。但在那之后,它抛出了下面的错误。当我使用Feign或Webclient同步调用servces时,也遇到了同样的问题。

2023-10-30T05:19:59.789+05:30  INFO 10856 --- [           main] c.javatechie.SwiggyGatewayApplication    : Started SwiggyGatewayApplication in 3.752 seconds (process running for 4.03)
java.lang.IllegalStateException: block()/blockFirst()/blockLast() are blocking, which is not supported in thread reactor-http-nio-3
    at reactor.core.publisher.BlockingSingleSubscriber.blockingGet(BlockingSingleSubscriber.java:83)
    at reactor.core.publisher.Mono.block(Mono.java:1710)
    at org.springframework.cloud.loadbalancer.blocking.client.BlockingLoadBalancerClient.choose(BlockingLoadBalancerClient.java:163)
    at org.springframework.cloud.loadbalancer.blocking.client.BlockingLoadBalancerClient.execute(BlockingLoadBalancerClient.java:74)
    at org.springframework.cloud.client.loadbalancer.LoadBalancerInterceptor.intercept(LoadBalancerInterceptor.java:56)
    at org.springframework.http.client.InterceptingClientHttpRequest$InterceptingRequestExecution.execute(InterceptingClientHttpRequest.java:87)
    at org.springframework.http.client.InterceptingClientHttpRequest.executeInternal(InterceptingClientHttpRequest.java:71)
    at org.springframework.http.client.AbstractBufferingClientHttpRequest.executeInternal(AbstractBufferingClientHttpRequest.java:48)
    at org.springframework.http.client.AbstractClientHttpRequest.execute(AbstractClientHttpRequest.java:66)
    at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:862)
    at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:764)
    at org.springframework.web.client.RestTemplate.getForObject(RestTemplate.java:378)
    at com.javatechie.filter.AuthenticationFilter.lambda$apply$0(AuthenticationFilter.java:42)

RestTemplateConfiguration

@Configuration
class RestTemplateConfiguration {
    @Bean
    @LoadBalanced
    public RestTemplate restTemplate() {
        return new RestTemplate(new BufferingClientHttpRequestFactory(new HttpComponentsClientHttpRequestFactory()));
    }
}


在这个类似云网关的应用程序中,是否可以使用RestTemplate或Feignclient或Webclient等通过服务名称同步调用服务?

0wi1tuuw

0wi1tuuw1#

最后,我注意到,由于WebFlux是响应式的,我需要这样做。所以,我做了以下更改,现在它工作得很好。

1.添加负载均衡依赖

<dependency>
   <groupId>org.springframework.cloud</groupId>
   <artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>

字符串

2.添加WebClient配置。

@Configuration
class WebClientConfig {

    @Bean
    @LoadBalanced
    public WebClient.Builder loadBalancedWebClientBuilder() {
        return WebClient.builder();
    }
}

3.通过WebClient使用service-name调用外部微服务,如下所示

import jakarta.ws.rs.core.HttpHeaders;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.client.WebClient;

@Component
public class AuthenticationFilter extends AbstractGatewayFilterFactory<AuthenticationFilter.Config> {

    private WebClient webClient;

    public AuthenticationFilter() {
        super(Config.class);
    }
    
    @Autowired
    public AuthenticationFilter(WebClient.Builder webClientBuilder) {
        super(Config.class);
        this.webClient = webClientBuilder.build();
    }

    @Override
    public Config newConfig() {
        return new Config();
    }

    @Override
    public GatewayFilter apply(Config config) {
        return (exchange, chain) -> {
            String authHeader = exchange.getRequest().getHeaders().getFirst(HttpHeaders.AUTHORIZATION);

            if (authHeader != null && authHeader.startsWith("Bearer ")) {
                authHeader = authHeader.substring(7);
            }

            String expectedRole = config.role;
            String authServiceUrl = "http://YOUR-APPLICATION-SERVICE-NAME";

            return this.webClient
                    .get()
                    .uri(authServiceUrl + "/auth/doOp?token=" + authHeader + "&role=" + expectedRole)
                    .retrieve()
                    .bodyToMono(Boolean.class)
                    .flatMap(response -> {
                        // Do further operations on microservice response if needed
                        return chain.filter(exchange);
                    })
                    .onErrorResume(throwable -> {
                        throw new RuntimeException("un authorized access to application");
                    });
        };
    }

    public static class Config {
        private String role;
        public String getRole() {
            return role;
        }
        public void setRole(String role) {
            this.role = role;
        }
    }
}


我在这里分享了一个示例项目:https://github.com/namalfernandolk/cloud-gateway-demo.git

相关问题