SpringCloud Gateway etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster
SpringCloud Gateway etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster

18 Nisan 2022 Pazartesi

SpringCloud Gateway GlobalFilter Arayüzü

Giriş
GlobalFilter ve GatewayFilter benziyorlar

Örnek
Şöyle yaparız
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;

public class PostGlobalFilter implements GlobalFilter, Ordered {

  ...

  @Override
  public int getOrder() {
    return 0;
  }
}
Metodun içi şöyle
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
  return chain.filter(exchange).then(Mono.fromRunnable(()->{
    ServerHttpResponse response = exchange.getResponse();
    HttpStatus responseStatus = response.getStatusCode();
    if(responseStatus.equals(HttpStatus.BAD_REQUEST)){
      String newResponseBody =
      "<body>\n" +
      "<h1 style=\"color:red;text-align:center\">Bad Request </h1>\n" +
      "<p>If you are seeing this page it means response body is modified.</p>\n" +
      "</body>";

      DataBuffer dataBuffer = response.bufferFactory()
        .wrap(newResponseBody.getBytes(StandardCharsets.UTF_8));
      response.getHeaders().setContentLength(newResponseBody.length());
      response.writeWith(Mono.just(dataBuffer)).subscribe();
      exchange.mutate().response(response).build();
    }
  }));
}


28 Eylül 2021 Salı

SpringCloud Gateway RequestRateLimiter Sınıfı - API Rate Limiter İçin Kullanılır

Giriş
Şu satırı dahil ederiz
import org.springframework.cloud.gateway.filter.ratelimit.RateLimiter;
import org.springframework.cloud.gateway.filter.ratelimit.RedisRateLimiter;
Maven
Şöyle yaparız. RequestRateLimiter altta Redis kullanır. Dolayısıyla data-redis gerekir.
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifatId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>
Açıklaması şöyle
RequestRateLimiter is one of the many gateway filters offered by SCG. The implementation determines whether a request is allowed to proceed or has exceeded its limit. ...
the gateway comes with one that uses a user’s Principal name. A secured gateway is needed to resolve a user’s principal name, but you have the option to implement the KeyResolver interface to instead resolve a different key from the ServerWebExchange
You can point to a custom KeyResolver bean (for example, named customKeyResolver) in the configuration by using a SPEL #{@customKeyResolver} expression. 
RequestRateLimiter sınfı RequestRateLimiterGatewayFilterFactory tarafından yaratılır

Açıklaması şöyle
The provided Redis implementation lets you define the request rate at which users can make calls within a certain time period. It also makes it possible to accommodate sporadic demands while constrained by the defined consumption rate. For example, a configuration can define a replenish rate of 500 requests per second by setting the redis-rate-limiter.replenishRate=500 property and a burst capacity of 1000 request per second by setting the redis-rate-limiter.burstCapacity=1000 property. Doing so limits consumption to 500 requests every second. If a burst in the number of requests occurs, only 1,000 requests are allowed. However, because 1,000 requests are a quota of 2 seconds, the gateway would not route requests for the next second. The configuration also lets you define how many tokens a request would cost by setting the property redis-rate-limiter.requestedTokens property. Typically, it is set to 1.

To use a gateway with a request limiting feature, it needs to be configured with the RequestRateLimiter gateway filter. 
Yani şöyle yaparız
spring:
cloud: gateway: routes: - id: route1 uri: http://localhost:8081 predicates: - Path=/backend filters: - name: RequestRateLimiter args: redis-rate-limiter.replenishRate: 500 redis-rate-limiter.burstCapacity: 1000 redis-rate-limiter.requestedTokens: 1
Açıklaması şöyle
burstCapacity, the total capacity of the token bucket.
replenishRate, the average rate at which the token bucket is filled per second.

KeyResolver  Arayüzü
Şu satırı dahil ederiz
import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;
Eğer KeyResolver kullanmak istersek şöyle yaparız
spring:
cloud: gateway: routes: - id: route1 uri: http://localhost:8081 predicates: - Path=/backend filters: - name: RequestRateLimiter args: rate-limiter: "#{customRateLimiter}" key-resolver: "#{customKeyResolver}" @Bean public KeyResolver customKeyResolver { return exchange -> .... // returns a Mono of String }
Çok detaylı bir örnek burada
Örnek
Şöyle yaparız
server:
  port: 8081
spring:
  cloud:
    gateway:
      routes:
      - id: limit_route
        uri: http://httpbin.org:80/get
        predicates:
        - After=2017-01-20T17:42:47.789-07:00[America/Denver]
        filters:
        - name: RequestRateLimiter
          args:
            key-resolver: '#{@hostAddrKeyResolver}'
            redis-rate-limiter.replenishRate: 1
            redis-rate-limiter.burstCapacity: 3
  application:
    name: gateway-limiter
  redis:
    host: localhost
    port: 6379
    database: 0
Açıklaması şöyle
key-resolver, the name of the bean object of the resolver for the throttled key. It uses SpEL expressions to get bean objects from the Spring container based on #{@beanName}.
Hostname özelliğine göre sınırlamak için şöyle yaparız
public class HostAddrKeyResolver implements KeyResolver {

  @Override
  public Mono<String> resolve(ServerWebExchange exchange) {
    return Mono.just(exchange.getRequest().getRemoteAddress()
      .getAddress().getHostAddress());
  }

}

@Bean
public HostAddrKeyResolver hostAddrKeyResolver() {
  return new HostAddrKeyResolver();
}
URI'ye göre sınırlamak için şöyle yaparız
public class UriKeyResolver  implements KeyResolver {

  @Override
  public Mono<String> resolve(ServerWebExchange exchange) {
    return Mono.just(exchange.getRequest().getURI().getPath());
  }
}

@Bean
public UriKeyResolver uriKeyResolver() {
  return new UriKeyResolver();
}
Örnek
Şöyle yaparız
import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;
import org.springframework.web.server.ServerWebExchange;

import com.auth0.jwt.JWT;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import io.netty.util.internal.StringUtil;
import reactor.core.publisher.Mono;

public class CustomerKeyResolver implements KeyResolver {

  @Override
  public Mono<String> resolve(ServerWebExchange exchange) {
    String apiName = exchange.getRequest().getPath().toString();

    List<String> customerIds = exchange.getRequest().getHeaders().get("X-Customer-Id");
    if (customerIds != null && ...) {
      return Mono.just(customerIds.get(0) + StringUtil.COMMA + apiName);
    }

    List<String> authHeaders = exchange.getRequest().getHeaders().get("Authorization");
    if (authHeaders != null && ...) {
      ...
    }

    return Mono.just(StringUtil.EMPTY_STRING);
  }
}

19 Eylül 2021 Pazar

SpringCloud Gateway application.properties default-filters Alanı

default-filters
Örnek
Şöyle yaparız. Böylece authentication token servislere de geçilir.
spring:
  cloud:
    gateway:
      default-filters:
        - TokenRelay
Örnek
Şöyle yaparız
spring:
  main:
    web-application-type: reactive
  profiles:
    active: dev
  cloud:
    gateway:
      default-filters:
        - DedupeResponseHeader=Access-Control-Allow-Credentials Access-Control-Allow-Origin
      globalcors:
        corsConfigurations:
          '[/**]':
              allowedOrigins: "*"
              allowedMethods: "*"
              allowedHeaders: "*"
      httpclient:
        pool:
          max-idle-time: 10s
      ssl:
        useInsecureTrustManager: true
      filter:
        StripPrefix: 1
        remove-non-proxy-headers:
          headers:
            - Keep-Alive
            - TE
            - Trailer
            - Transfer-Encoding
            - Upgrade
            - Connection
            - Host
      routes:
        - id: ws
          uri: ws://192.168.0.125:5554
          predicates:
            - Path=/websocket/**
        - id: request_size_route
          uri: http://192.168.0.125:5554
          predicates:
            - Path=/**
StripPrefix
Baştaki ön eklerden kaç tanesinin silineceğini belirtir. Örneğin istek 
"product-service.yourplatform.com/product-service/products" adresine gelseydi ve biz
"product-service/products" adresine yönlendirmek isteseydik, StripPrefix=1 yapardık

Örnek
/products adresi için Şöyle yaparız
spring:
  cloud:
    gateway:
      routes:
        - id: products
          uri: https://dummyjson.com/products
          predicates:
            - Path=/products
          filters:
            - StripPrefix=0
aynı şeyi bu sefer "products/java" adresi için kodla şöyle yaparız
@SpringBootApplication
public class GatewayApplication {

  public static void main(String[] args) {
    SpringApplication.run(GatewayApplication.class, args);
  }

  @Bean
  public RouteLocator routes(RouteLocatorBuilder builder) {
    return builder.routes()
      .route(p -> p.path("/products-java")
                   .filters(f -> f.setPath("/products"))
                   .uri("https://dummyjson.com"))
      .build();
  }
}
Şu iki adres te aynı yere yönlendirilir
ahttp://localhost:9000/products
http://localhost:9000/products-java



SpringCloud Gateway RouteLocatorBuilder Sınıfı

Giriş
Şu satırı dahil ederiz
import org.springframework.cloud.gateway.route.RouteLocator;
Bu sınıf yerine application.properties de kullanılabilir.

routes metodu
1. route Kullanımı
Örnek
Şöyle yaparız
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;

@Configuration
public class GatewayMicroservicesConfig {

  public RouteLocator gatewayConfig(RouteLocatorBuilder locatorBuilder) {

    return locatorBuilder.routes()
      .route(r -> r.path("/firstmicroservice/**").uri("http://localhost:8081/"))
      .route( r -> r.path("/secondmicroservice/**").uri("http://localhost:8082/"))
       .build();
    }
}
Aynı şeyi  application.properties ile şöyle yaparız
# application.properties file for spring cloud gateway 
spring.application.name=gateway
sever.port=8080

## microservices mapping ##
spring.cloud.gateway.routes[0].id=microservice-one
spring.cloud.gateway.routes[0].uri=http://localhost:8081/
spring.cloud.gateway.routes[0].predicates[0]=Path=/firstmicroservice/**

spring.cloud.gateway.routes[1].id=microservice-two
spring.cloud.gateway.routes[1].uri=http://localhost:8082/
spring.cloud.gateway.routes[1].predicates[0]=Path=/secondmicroservice/
Örnek
Şöyle yaparız
@Bean
public RouteLocator gatewayRoutes(RouteLocatorBuilder builder) {
  return builder.routes()
    .route(r -> r.path("/employee/**")
                 .uri("http://localhost:8081/")
                 .id("employeeModule"))

    .route(r -> r.path("/consumer/**")
                 .uri("http://localhost:8082/")
                 .id("consumerModule"))
    .build();
}
Aynısını application.properties şeklinde yapsaydık şöyle olurdu
spring:
  cloud:
    gateway:
      routes:
      - id: employeeModule
        uri: http://localhost:8081/
        predicates:
        - Path=/employee/**
      - id: consumerModule
        uri: http://localhost:8082/
        predicates:
        - Path=/consumer/**
2. filter Kullanımı
Açıklaması şöyle. Yani Http isteğine ekleme, çıkarma, değişiklikler yapılabilir
In addition to creating a route, RouteLocatorBuilder allows you to add various predicates and filters.
Örnek
Şöyle yaparız
@Bean
public RouteLocator myRoutes(RouteLocatorBuilder builder) {
  return builder.routes()
    .route(p -> p
      .path("/get")
      .filters(f -> f.addRequestHeader("Hello", "World"))
      .uri("http://httpbin.org:80"))
    .build();
}
Açıklaması şöyle
The route created above can make requests for “/get” forwarded to “http://httpbin.org/get". On the route configuration, we added a filter, which will add a header to the request, the key is hello, and the value is world.

Örnek
Şöyle yaparız
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.security.oauth2.gateway.TokenRelayGatewayFilterFactory;


@EnableEurekaClient
@SpringBootApplication
public class ApiGatewayApplication {

  @Bean
  public RouteLocator customRouteLocator(RouteLocatorBuilder builder,
                                         TokenRelayGatewayFilterFactory filterFactory) {
    return builder.routes()
      .route("car-service", r -> r.path("/cars")
      .filters(f -> f.filter(filterFactory.apply()))
      .uri("lb://car-service"))
      .build();
  }  
}
3. Hystrix Kullanımı
Fallback tanımlamak içindir
Örnek
Şöyle yaparız
@Bean
public RouteLocator myRoutes(RouteLocatorBuilder builder) {
  String httpUri = "http://httpbin.org:80";
  return builder.routes()
    .route(p -> p
      .path("/get")
      .filters(f -> f.addRequestHeader("Hello", "World"))
      .uri(httpUri))
    .route(p -> p
      .host("*.foo.com")
      .filters(f -> f
        .hystrix(config -> config
          .setName("mycmd")
          .setFallbackUri("forward:/fallback")))
        .uri(httpUri))
    .build();
}
Fallback şöyledir
@RequestMapping("/fallback")
public Mono<String> fallback() {
  return Mono.just("fallback");
}
İsteği şöyle göndeririz
curl --dump-header - --header 'Host: www.foo.com' http://localhost:8080/delay/3