快速开始

引入依赖(必须排除springmvc的包)

  1. <!--gateway-->
  2. <dependency>
  3. <groupId>org.springframework.cloud</groupId>
  4. <artifactId>spring-cloud-starter-gateway</artifactId>
  5. </dependency>
  6. <!--nacos-->
  7. <dependency>
  8. <groupId>com.alibaba.cloud</groupId>
  9. <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
  10. </dependency>

配置yaml

server:
  port: 8888
spring:
  application:
    name: mall-gateway
  cloud:
    nacos:
      discovery:
        server-addr: 139.198.123.65:8848
    gateway:
      discovery:
        locator:
          #开启微服务名称来访问,默认为false,不建议用使用
          enabled: true
      #是否开启网关
      enabled: true

测试
image.png

路由断言工厂配置

https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#gateway-request-predicates-factories

路径匹配

spring:
    cloud:
    gateway:
      #设置路由
      routes:
        #路由id,全局唯一
        - id: order_router
          #目标微服务的请求与端口与地址
          #uri: http://localhost:8020
          #lb 整合负载均衡过期ribbon,loadbalancer
          uri: lb://mall-order
          predicates:
            - Path=/order/**

时间匹配

spring:
    cloud:
    gateway:
      #设置路由
      routes:
        #路由id,全局唯一
        - id: order_router
          #目标微服务的请求与端口与地址
          #uri: http://localhost:8020
          #lb 整合负载均衡过期ribbon,loadbalancer
          uri: lb://mall-order
          predicates:
            #匹配在指定日期时间之后发生的请求 入参是ZonedDateTime类型
            - After=2022-04-01T08:18:29.833+08:00[Asia/Shanghai]

Cookie匹配

spring:
    cloud:
    gateway:
      #设置路由
      routes:
        #路由id,全局唯一
        - id: order_router
          #目标微服务的请求与端口与地址
          #uri: http://localhost:8020
          #lb 整合负载均衡过期ribbon,loadbalancer
          uri: lb://mall-order
          predicates:
            #cookie匹配
            - Cookie=username,tong

Header匹配

spring:
    cloud:
    gateway:
      #设置路由
      routes:
        #路由id,全局唯一
        - id: order_router
          #目标微服务的请求与端口与地址
          #uri: http://localhost:8020
          #lb 整合负载均衡过期ribbon,loadbalancer
          uri: lb://mall-order
          predicates:
            #Header匹配 请求中带有X-Request-Id,其值与 \d+ 正则表达式正整数匹配
            - Header=X-Request-Id,\d+

自定义路由断言工厂

@Component
@Slf4j
public class CheckAuthRoutePredicateFactory extends AbstractRoutePredicateFactory<CheckAuthRoutePredicateFactory.Config> {
    public CheckAuthRoutePredicateFactory() {
        super(Config.class);
    }

    @Override
    public Predicate<ServerWebExchange> apply(Config config) {
        log.info("调用CheckAuthRoutePredicateFactory" + config.getName());
        return serverWebExchange -> config.getName().equals("tong");
    }

    /**
     * 需要定义一个内部类,该类用于封装application.yml中的配置
     */
    public static class Config {

        private String name;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }
    }

    /**
     * 快捷配置
     *   - CheckAuth: tong
     * @return
     */
    //@Override
    //public List<String> shortcutFieldOrder() {
    //    return Collections.singletonList("name");
    //}
}
spring:
    cloud:
    gateway:
      #设置路由
      routes:
        #路由id,全局唯一
        - id: order_router
          #目标微服务的请求与端口与地址
          #uri: http://localhost:8020
          #lb 整合负载均衡过期ribbon,loadbalancer
          uri: lb://mall-order
          predicates:
            #自定义断言工厂
            - name: CheckAuth
              args:
                name: tong

            #- CheckAuth: tong

过滤器工厂

添加请求参数与请求头

spring:
  cloud:
    gateway:
      #设置路由
      routes:
        #路由id,全局唯一
        - id: order_router
          #配置过滤器工厂
          filters:
            #添加请求头
            - AddRequestHeader=X-Request-color,red
            #添加请求参数
            - AddRequestParameter=color,blue

添加&去除路径

spring:
  cloud:
    gateway:
      #设置路由
      routes:
        #路由id,全局唯一
        - id: order_router
          filters:
            #添加前缀 对应的微服务需要配置context-path
            - PrefixPath=/mall-order
            #去掉一层前缀
            - StripPrefix=1

重定向

spring:
  cloud:
    gateway:
      #设置路由
      routes:
        #路由id,全局唯一
        - id: order_router
          filters:
            #重定向到百度
            - RedirectTo=302,https://www.baidu.com

自定义过滤器工厂

spring:
  cloud:
    gateway:
      #设置路由
      routes:
        #路由id,全局唯一
        - id: order_router
          filters:
            #配置自定义过滤器工厂
            - CheckAuth=tong,shuaige
@Component
@Slf4j
public class CheckAuthGatewayFilterFactory extends AbstractNameValueGatewayFilterFactory {
    @Override
    public GatewayFilter apply(NameValueConfig config) {
        return (exchange, chain) -> {
            log.info("调用AbstractNameValueGatewayFilterFactory:" + config.getName() + config.getValue());
            // TODO
            return chain.filter(exchange);
        };
    }
}

自定义GlobalFilter

@Component
@Slf4j
public class CheckIpFilter implements GlobalFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        HttpHeaders headers = exchange.getRequest().getHeaders();
        //模拟IP的访问限制,即不在白名单中就不能调用的需求
        if (getIp(headers).equals("127.0.0.1")) {
            log.info("---非法访问---");
            ServerHttpResponse response = exchange.getResponse();
            byte[] bytes = new String("---非法访问---").getBytes();
            response.setStatusCode(HttpStatus.NOT_ACCEPTABLE);
            DataBuffer buffer = response.bufferFactory().wrap(bytes);
            response.getHeaders().add("Context-Type", "application/json;charset=UTF-8");
            return exchange.getResponse().writeWith(Mono.just(buffer));
        }
        return chain.filter(exchange);
    }

    private String getIp(HttpHeaders headers) {
        return headers.getHost().getHostName();
    }

    @Override
    public int getOrder() {
        return 0;
    }
}
@Component
@Slf4j
public class CheckAuthFilter implements GlobalFilter {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //校验请求头中的token
        List<String> token = exchange.getRequest().getHeaders().get("token");
        log.info("token:" + token);
        if (token.isEmpty()) {
            return null;
        }
        return chain.filter(exchange);
    }
}

跨域

spring实现

@Configuration
public class CorsConfig {
    @Bean
    public CorsWebFilter corsWebFilter() {
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.addAllowedHeader("*");
        corsConfiguration.addAllowedOrigin("*");
        corsConfiguration.addAllowedMethod("*");
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(new PathPatternParser());
        source.registerCorsConfiguration("/**", corsConfiguration);
        return new CorsWebFilter(source);
    }
}

Gateway配置

spring:
  cloud:
    gateway:
      #跨域
      globalcors:
        cors-configurations: 
          '[/**]':
            allowedOrigins: "*"
            allowedMethods:
              - GET
              - POST
              - DELETE
              - PUT
              - OPTION

网管限流(问题贼鸡儿多)

pom

        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
        </dependency>

yaml

spring:
  cloud:
    nacos:
      discovery:
        server-addr: 139.198.123.65:8848
    sentinel:
      transport:
        dashboard: http://localhost:8080

注入对应的 SentinelGatewayFilter 实例以及 SentinelGatewayBlockExceptionHandler 实例

@Configuration
public class SentinelConfig {
    private final List<ViewResolver> viewResolvers;
    private final ServerCodecConfigurer serverCodecConfigurer;

    public SentinelConfig(List<ViewResolver> viewResolvers, ServerCodecConfigurer serverCodecConfigurer) {
        this.viewResolvers = viewResolvers;
        this.serverCodecConfigurer = serverCodecConfigurer;
    }

    /**
     * 限流异常处理器
     * @return
     */
    @Bean
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() {
        return new SentinelGatewayBlockExceptionHandler(viewResolvers,serverCodecConfigurer);
    }

    @Bean
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public GlobalFilter sentinelGatewayFilter(){
        return new SentinelGatewayFilter();
    }
}

GatewayRuleManager.loadRules(rules) 手动加载网关规则

    @PostConstruct
    public void doInit() {
        //初始化自定义的api
        initCustomizedApis();
        //初始化网关限流规则
        initGatewayRules();
        //自定义限流异常处理器
        initBlockRequestHandler();
    }

    private void initBlockRequestHandler() {
        BlockRequestHandler blockRequestHandler = new BlockRequestHandler() {
            @Override
            public Mono<ServerResponse> handleRequest(ServerWebExchange exchange, Throwable t) {
                HashMap<String, String> result = new HashMap<>();
                result.put("code", String.valueOf(HttpStatus.TOO_MANY_REQUESTS.value()));
                result.put("msg", HttpStatus.TOO_MANY_REQUESTS.getReasonPhrase());

                return ServerResponse.status(HttpStatus.TOO_MANY_REQUESTS)
                        .contentType(MediaType.APPLICATION_JSON)
                        .body(BodyInserters.fromValue(result));
            }
        };
        //设置自定义异常处理器
        GatewayCallbackManager.setBlockHandler(blockRequestHandler);
    }

    private void initGatewayRules() {
        Set<GatewayFlowRule> rules = new HashSet<>();
        //resource:资源名称,可以是网关中的 route 名称或者用户自定义的 API 分组名称。
        //count:限流阈值
        //intervalSec:统计时间窗口,单位是秒,默认是 1 秒。
        rules.add(new GatewayFlowRule("order_route")
                .setCount(2)
                .setIntervalSec(1)
        );
        // 加载网关规则
        GatewayRuleManager.loadRules(rules);
    }

    private void initCustomizedApis() {
        Set<ApiDefinition> definitions = new HashSet<>();
        ApiDefinition api = new ApiDefinition("order_router")
                .setPredicateItems(new HashSet<ApiPredicateItem>() {{
                    add(new ApiPathPredicateItem().setPattern("/order/**")
                            .setMatchStrategy(SentinelGatewayConstants.URL_MATCH_STRATEGY_PREFIX));
                }});
        definitions.add(api);
        GatewayApiDefinitionManager.loadApiDefinitions(definitions);
    }