一、微服务架构-网关spring cloud gateway

4 篇文章 0 订阅
1 篇文章 0 订阅

这篇文章讲述了如何简单地使用Spring Cloud Gateway,来源于Spring Cloud官方案例,地址https://spring.io/guides/gs/gateway 

一、简介

gateway是什么:Spring Cloud Gateway是Spring官方基于Spring 5.0,Spring Boot 2.0和Project Reactor等技术开发的网关,Spring Cloud Gateway旨在为微服务架构提供一种简单而有效的统一的API路由管理方式。这里需要注意一下gateway使用的netty+webflux实现,不要加入web依赖,需要加入webflux依赖。

gateway与zuul的区别的简单比较:gateway使用的是异步请求,zuul是同步请求,gateway的数据封装在ServerWebExchange里,zuul封装在RequestContext里。
 

二、配置转发路由

1、通过配置文件转发路由

spring:
  cloud:
    gateway:
    # 配置所有路由的默认过滤器 这里配置的是gatewayFilter
      default-filters:
      routes:
      - id: server-test  # 服务的id
        uri: lb://server-test #服务的application名称
        order: 0 #路由级别
        predicates:
        - Path=/bus/**  #前缀
        filters:
        - StripPrefix=1 #去前缀 去几层,1表示去bus **其他留下

2、通过修改启动类转发路由

/**
 * gateway 方式实现
 */
@SpringBootApplication
public class ServiceGatewayApplication {
 
    public static void main(String[] args) {
        SpringApplication.run(ServiceGatewayApplication.class, args);
    }
 
    @Bean
    public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
        StripPrefixGatewayFilterFactory.Config config =
                new StripPrefixGatewayFilterFactory.Config();
        config.setParts(1);
        return builder.routes()
                .route("test", a -> a.path("/test/**")
                        .filters(b -> b.stripPrefix(1))
                        .uri("http://localhost:8762"))
                .route("api-test2", r -> r.path("/api-test2/**")
                        .filters(f -> f.stripPrefix(1))
                        .uri("http://localhost:8762"))
                .route("api-test3", r -> r.path("/api-test3/**").
                        filters(f -> f.stripPrefix(1)).
                        uri("lb://service-test"))
                .build();
    }
}

3、使用Hystrix 

在spring cloud gateway中可以使用Hystrix。Hystrix是 spring cloud中一个服务熔断降级的组件,在微服务系统有着十分重要的作用。
Hystrix是 spring cloud gateway中是以filter的形式使用的,代码如下:

/**
 * gateway 方式实现
 */
@SpringBootApplication
public class ServiceGatewayApplication {
 
    public static void main(String[] args) {
        SpringApplication.run(ServiceGatewayApplication.class, args);
    }
 
    @Bean
    public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
        StripPrefixGatewayFilterFactory.Config config =
                new StripPrefixGatewayFilterFactory.Config();
        config.setParts(1);
        return builder.routes()
                .route("test", a -> a.path("/test/**")
                        .filters(b -> b.stripPrefix(1))
                        .uri("http://localhost:8762"))
                .route("api-test2", r -> r.path("/api-test2/**")
                        .filters(f -> f.stripPrefix(1))
                        .uri("http://localhost:8762"))
                .route("api-test3", r -> r.path("/api-test3/**").
                        filters(f -> f.stripPrefix(1)).
                        uri("lb://service-test"))
               .route(p -> p
                .host("*.hystrix.com")
                .filters(f -> f
                    .hystrix(config -> config
                        .setName("mycmd")
                        .setFallbackUri("forward:/fallback")))
                .uri(httpUri))
            .build();
    }
}

在上面的代码中,我们使用了另外一个router,该router使用host去断言请求是否进入该路由,当请求的host有“*.hystrix.com”,都会进入该router,该router中有一个hystrix的filter,该filter可以配置名称、和指向性fallback的逻辑的地址,比如本案例中重定向到了“/fallback”。

现在写的一个“/fallback”的l逻辑:


 @RequestMapping("/fallback")
    public Mono<String> fallback() {
        return Mono.just("fallback");
    }

因此带xxx.hystrix.com的请求执行了hystrix的fallback的逻辑。

三、配置过滤器
 

过滤器:gateway有两种filter,一种是GlobalFilter一种是GatewayFilter,全局过滤器默认对所有路由有效,gatewayFilter需要进行指定。

filter的作用和生命周期:

       由filter工作流程点,可以知道filter有着非常重要的作用,在“pre”类型的过滤器可以做参数校验、权限校验、流量监控、日志输出、协议转换等,在“post”类型的过滤器中可以做响应内容、响应头的修改,日志的输出,流量监控等。首先需要弄清一点为什么需要网关这一层,这就不得不说下filter的作用了。

1、GlobalFilter 配置全局过滤器

/**
*  
*  配置全局过滤器
**/
@Configuration
@Slf4j
public class AccessGatewayFilter implements GlobalFilter{
  
      @Override
    public Mono<Void> filter(ServerWebExchange serverWebExchange, GatewayFilterChain gatewayFilterChain) {
        //方法
        return gatewayFilterChain.filter(serverWebExchange.mutate().request(build).build());
    }
}

注意:在这里可以实现记录日志和访问权限校验等

2.自定义GatewayFilter

GatewayFiltery有两种类型的filter,分别为pre和post类型,以下提供一个demo的配置

定义PreGatewayFilter:

public class PreGatewayFilterFactory extends AbstractGatewayFilterFactory {
 
      public PreGatewayFilterFactory() {
          super(Config.class);
      }
 
      public GatewayFilter apply() {
          return apply(o -> {
          });
      }
      @Override
      public GatewayFilter apply(Config config) {
          // grab configuration from Config object
          return (exchange, chain) -> {
              //If you want to build a "pre" filter you need to manipulate the
              //request before calling change.filter  ServerHttpRequest.Builder builder = exchange.getRequest().mutate();
              builder.header("GatewayFilter", "PreGatewayFilterFactory success");
              //use builder to manipulate the request
              return chain.filter(exchange.mutate().request(builder.build()).build());
          };
      }
        public static class Config {
            //Put the configuration properties for your filter here
      }
}

定义PostGatewayFilter:

public class PostGatewayFilterFactory extends AbstractGatewayFilterFactory {
 
    private Logger logger = LoggerFactory.getLogger(PostGatewayFilterFactory.class);
 
    public PostGatewayFilterFactory() {
        super(Config.class);
    }
 
    public GatewayFilter apply() {
        return apply(o -> {
        });
    }
 
    @Override
    public GatewayFilter apply(Config config) {
        return (exchange, chain) -> {
          logger.info("PostGatewayFilter...");
          return chain.filter(exchange).then(Mono.fromRunnable(() -> {
              ServerHttpResponse response = exchange.getResponse();
            //Manipulate the response in some way
            }));
          };
    }
 
    public static class Config {
        //Put the configuration properties for your filter here
  }
}

四、跨域配置

import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.gateway.discovery.DiscoveryClientRouteDefinitionLocator;
import org.springframework.cloud.gateway.discovery.DiscoveryLocatorProperties;
import org.springframework.cloud.gateway.route.RouteDefinitionLocator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.codec.ServerCodecConfigurer;
import org.springframework.http.codec.support.DefaultServerCodecConfigurer;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.cors.reactive.CorsUtils;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;
 
/**
 * 跨域允许
 */
@Configuration
public class CorsConfig {
    private static final String MAX_AGE = "18000L";
 
    @Bean
    public WebFilter corsFilter() {
        return (ServerWebExchange ctx, WebFilterChain chain) -> {
            ServerHttpRequest request = ctx.getRequest();
            if (CorsUtils.isCorsRequest(request)) {
                HttpHeaders requestHeaders = request.getHeaders();
                ServerHttpResponse response = ctx.getResponse();
                HttpMethod requestMethod = requestHeaders.getAccessControlRequestMethod();
                HttpHeaders headers = response.getHeaders();
                headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, requestHeaders.getOrigin());
                headers.addAll(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS, requestHeaders
                        .getAccessControlRequestHeaders());
                if(requestMethod != null){
                    headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, requestMethod.name());
                }
                headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS, "true");
                headers.add(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, "*");
                headers.add(HttpHeaders.ACCESS_CONTROL_MAX_AGE, MAX_AGE);
                if (request.getMethod() == HttpMethod.OPTIONS) {
                    response.setStatusCode(HttpStatus.OK);
                    return Mono.empty();
                }
 
            }
            return chain.filter(ctx);
        };
    }
 
    @Bean
    public ServerCodecConfigurer serverCodecConfigurer() {
        return new DefaultServerCodecConfigurer();
    }
 
    /**
     * 如果使用了注册中心(如:Eureka),进行控制则需要增加如下配置
     */
    @Bean
    public RouteDefinitionLocator discoveryClientRouteDefinitionLocator(DiscoveryClient discoveryClient,
                                                                        DiscoveryLocatorProperties properties) {
        return new DiscoveryClientRouteDefinitionLocator(discoveryClient, properties);
    }
}

 

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值