三大核心概念

Route(路由)

路由是构建网关的基本模块,它由ID,目标URI,一系列的断言和过滤器组成,如果断言为true则匹配该路由

Predicate(断言)

参考的是java8的java.util.function.Predicate开发人员可以匹配HTTP请求中的所有内容(例如请求头或请求参数),如果请求与断言相匹配则进行路由

Filter(过滤)

指的是Spring框架中GatewayFilter的实例,使用过滤器,可以在请求被路由前或者之后对请求进行修改。

使用

一、 maven配置

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

二、 yml配置

spring:
  application:
    name: cloud-gateway
  cloud:
    gateway:
      httpclient:
        connect-timeout: 5000
        response-timeout: 5s

      routes:
        - id: devutil-api-project
          uri: lb://devutil-api-project
          predicates:
            - Path=/api/project/**

        - id: devutil-api-auth
          uri: lb://devutil-api-auth
          predicates:
            - Path=/api/auth/**

三、Predicate的使用

下面列举一些常用的

1.After Route Predicate(在该时间之后)

- After=2020-03-08T10:59:34.102+08:00[Asia/Shanghai]

2.Header Route Predicate

- Header=Token, \d+

四、 Filter

  • CrossFilter.java

    @Component
    public class CrossFilter implements GlobalFilter, Ordered {
        @Override
        public int getOrder() {
            return 0;
        }
    
        @Override
        public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
            ServerHttpRequest request = exchange.getRequest();
            HttpHeaders requestHeaders = request.getHeaders();
    
            HttpMethod requestMethod = requestHeaders.getAccessControlRequestMethod();
    
            ServerHttpResponse response = exchange.getResponse();
    
            HttpHeaders headers = response.getHeaders();
            headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, "*");
            headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS, "Token, Environment, Origin, X-Requested-With, Content-Type, Accept, Set-cookie");
            headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS, "true");
            headers.add(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, "Token, Environment");
            headers.add(HttpHeaders.CONTENT_TYPE, "application/json;charset=UTF-8");
            if (requestMethod != null) {
                headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, requestMethod.name());
            }
    
            if (request.getMethod() == HttpMethod.OPTIONS) {
                response.setStatusCode(HttpStatus.OK);
                return Mono.empty();
            }
            return chain.filter(exchange);
        }
    }
    
  • TokenFilter.java

    @Component
    public class TokenFilter implements GlobalFilter, Ordered {
        @Autowired
        PathService pathService;
    
        @Autowired
        FeignAuthService authService;
    
        @Autowired
        PermService permService;
    
        @Override
        public int getOrder() {
            return 1;
        }
    
        @Override
        public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
            ServerHttpRequest request = exchange.getRequest();
            ServerHttpResponse response = exchange.getResponse();
            HttpHeaders headers = request.getHeaders();
            MultiValueMap<String, String> params = request.getQueryParams();
    
            String path = request.getPath().toString();
            if (pathService.needToken(path)) {
                String token = headers.getFirst("Token");
    
                //token不为空
                if (!StringUtils.isBlank(token)) {
                    Info authInfo = authService.validate(token); //校验token
                    if (authInfo.getCode() == 0) {
                        //token校验成功
                        String userId = ((Map) (authInfo.getData())).get("_uid_").toString();
    
                        if (permService.judgePerm(path, userId, params)) {
                            //权限校验成功
                            return addUidParamFilter(exchange, chain, userId);
                        } else {
                            //无权限操作
                            Info resInfo = InfoUtil.getInfo(CommonError.PERM_LIMIT);
                            return output(response, ParseUtil.toJson(resInfo));
                        }
                    }
                }
    
                //token为空或校验失败
                Info resInfo = InfoUtil.getInfo(CommonError.TOKEN_ERROR);
                return output(response, ParseUtil.toJson(resInfo));
            }
            return chain.filter(exchange);
        }
    
    
        public Mono<Void> addUidParamFilter(ServerWebExchange exchange, GatewayFilterChain chain, String userId) {
            URI uri = exchange.getRequest().getURI();
            StringBuilder query = new StringBuilder();
            String originalQuery = uri.getRawQuery();
    
            if (!StringUtils.isBlank(originalQuery)) {
                query.append(originalQuery);
                if (originalQuery.charAt(originalQuery.length() - 1) != '&') {
                    query.append('&');
                }
            }
    
            query.append("_uid_");
            query.append('=');
            query.append(userId);
            try {
                URI newUri = UriComponentsBuilder.fromUri(uri)
                        .replaceQuery(query.toString())
                        .build(true)
                        .toUri();
    
                ServerHttpRequest request = exchange.getRequest().mutate().uri(newUri).build();
    
                return chain.filter(exchange.mutate().request(request).build());
            } catch (RuntimeException ex) {
                throw new IllegalStateException("Invalid URI query: \"" + query.toString() + "\"");
            }
        }
    
        public Mono<Void> output(ServerHttpResponse response, String message) {
            response.setStatusCode(HttpStatus.OK);
            byte[] bits = message.getBytes(StandardCharsets.UTF_8);
            DataBuffer buffer = response.bufferFactory().wrap(bits);
            return response.writeWith(Mono.just(buffer));
        }
    }
    

添加字段

    public Mono<Void> addUidParamFilter(ServerWebExchange exchange, GatewayFilterChain chain, String userId) {
        URI uri = exchange.getRequest().getURI();
        StringBuilder query = new StringBuilder();
        String originalQuery = uri.getRawQuery();

        if (!StringUtils.isBlank(originalQuery)) {
            query.append(originalQuery);
            if (originalQuery.charAt(originalQuery.length() - 1) != '&') {
                query.append('&');
            }
        }

        query.append("_uid_");
        query.append('=');
        query.append(userId);
        try {
            URI newUri = UriComponentsBuilder.fromUri(uri)
                    .replaceQuery(query.toString())
                    .build(true)
                    .toUri();

            ServerHttpRequest request = exchange.getRequest().mutate().uri(newUri).build();

            return chain.filter(exchange.mutate().request(request).build());
        } catch (RuntimeException ex) {
            throw new IllegalStateException("Invalid URI query: \"" + query.toString() + "\"");
        }
    }

添加header

        // 设置userId到request里,后续根据userId,获取用户信息
        ServerHttpRequest mutableReq = exchange.getRequest().mutate().header("userId", 6)
                .header("userName","李立").build();
        ServerWebExchange mutableExchange = exchange.mutate().request(mutableReq).build();
        return chain.filter(mutableExchange);

hhhhh