Spring Cloud Gateway 网关

Spring Cloud Gateway 网关

<!--网关--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency> <!--nacos discovery--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency>
server:  
  port: 8080  

spring:  
  application:  
    name: gateway  
  cloud:  
    nacos:  
      discovery:  
        server-addr: 192.168.87.133:8848  
    gateway:  
      routes:  
        - id: item-service  
          uri: lb://item-service  
          predicates:  
            - Path=/items/**,/search/**  
        - id: cart  
          uri: lb://cart-service  
          predicates:  
            - Path=/carts/**  
        - id: user  
          uri: lb://user-service  
          predicates:  
            - Path=/users/**,/addresses/**  
        - id: trade  
          uri: lb://trade-service  
          predicates:  
            - Path=/orders/**  
        - id: pay  
          uri: lb://pay-service  
          predicates:  
            - Path=/pay-orders/**  
      default-filters:  
        - AddRequestHeader=truth, blue

路由断言

路由过滤

登录实现

自定义过滤器

  • nettyRouting 优先级默认是最小的, 因此指定一个较大的数即可
package com.hmall.gateway.filters;  

import org.springframework.cloud.gateway.filter.GatewayFilterChain;  
import org.springframework.cloud.gateway.filter.GlobalFilter;  
import org.springframework.core.Ordered;  
import org.springframework.http.HttpHeaders;  
import org.springframework.http.server.reactive.ServerHttpRequest;  
import org.springframework.stereotype.Component;  
import org.springframework.web.server.ServerWebExchange;  
import reactor.core.publisher.Mono;  

@Component  
public class MyGlobalFilter implements GlobalFilter , Ordered {  

    @Override  
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {  
        // TODO 模拟登录检验  
        ServerHttpRequest request = exchange.getRequest();  
        HttpHeaders headers = request.getHeaders();  
        System.out.println(headers);  
        return chain.filter(exchange);  
    }  

    @Override  
    public int getOrder() {  
        return 0;  
    }  
}

实现

网关

  • 这里没有进行传递用户
package com.hmall.gateway.filters;  

import cn.hutool.core.text.AntPathMatcher;  
import com.hmall.common.exception.UnauthorizedException;  
import com.hmall.gateway.config.AuthProperties;  
import com.hmall.gateway.utils.JwtTool;  
import lombok.RequiredArgsConstructor;  
import org.springframework.cloud.gateway.filter.GatewayFilterChain;  
import org.springframework.cloud.gateway.filter.GlobalFilter;  
import org.springframework.core.Ordered;  
import org.springframework.http.HttpStatus;  
import org.springframework.http.server.RequestPath;  
import org.springframework.http.server.reactive.ServerHttpRequest;  
import org.springframework.stereotype.Component;  
import org.springframework.web.server.ServerWebExchange;  
import reactor.core.publisher.Mono;  

import java.util.List;  

@RequiredArgsConstructor  
@Component  
public class AuthGlobalFilter implements GlobalFilter, Ordered {  

    private final AuthProperties authProperties;  

    private final JwtTool jwtTool;  

    private final AntPathMatcher antPathMatcher = new AntPathMatcher();  
    @Override  
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {  
        // 1. 获取request对象  
        ServerHttpRequest request = exchange.getRequest();  
        // 2. 判断是否需要做登录拦截  
        List<String> excludePaths = authProperties.getExcludePaths();  
        RequestPath path = request.getPath();  
        if(isExclude(path.toString(),excludePaths)){  
            // 放行  
            return chain.filter(exchange);  
        }  
        // 3. 获取token  
        String token = null;  
        List<String> tokens = request.getHeaders().get("authorization");  
        if(tokens!=null&&!tokens.isEmpty()){  
            token = tokens.get(0);  
        }  

        Long userId = null;  
        // 4. 校验解析token, 获取用户信息  
        try {  
            userId = jwtTool.parseToken(token);  
        } catch (UnauthorizedException e) {  
            // 401 表示未登录  
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);  
            Mono<Void> voidMono = exchange.getResponse().setComplete();  
            return  voidMono;  
        }  
        // 5. 保存用户信息到请求头  
        System.out.println("userId = "+userId);  
        return chain.filter(exchange);  
    }  

    private boolean isExclude(String path, List<String> excludePaths) {  
        for (String excludePatten : excludePaths) {  
           if(antPathMatcher.match(excludePatten, path)){  
               return true;  
           }  

        }  
        return false;  
    }  

    @Override  
    public int getOrder() {  
        return 0;  
    }  
}

网关到微服务

  • 因为微服务都引用了 common 包, 因此将拦截器放到 common
public class UserInfoInterceptor implements HandlerInterceptor {  
    @Override  
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {  
        // 1. 获取登录信息  
        String userInfo = request.getHeader("user-info");  
        // 2. 判断是否获取了用户  
        if(StrUtil.isNotBlank(userInfo)){  
            // 3. 存入 threadLocal            UserContext.setUser(Long.valueOf(userInfo));  
        }  
        // 4. 放行  
        return HandlerInterceptor.super.preHandle(request, response, handler);  
    }  

    @Override  
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {  
        // 清理用户  

        UserContext.removeUser();  
        HandlerInterceptor.super.afterCompletion(request, response, handler, ex);  
    }  
}
@Configuration  
public class MvcConfig implements WebMvcConfigurer {  
    @Override  
    public void addInterceptors(InterceptorRegistry registry) {  
        registry.addInterceptor(new UserInfoInterceptor());  
    }  
}
  • 因为 common 包不会被微服务包扫描, 因此 @Configuration 不会生效, 因此

  • 网关引入 配置类后报错, 因为网关不是 springBoot , 因此设置自定配置类的生效条件

微服务到微服务

  • 是由 openFeign 发起的

  • 使 feign 配置类生效