网关gateway的使用

参考gateway使用
整合auth2:整合auth2
https://blog.csdn.net/weixin_43627706/article/details/124836962

gateway使用:

网关的作用

  • 作为API接口服务请求的接入点,管理所有的接入请求
  • 所有的业务服务都可以在这里被调用
  • 实现安全、验证、路由、过滤、流控,缓存等策略,进行一些必要的中介处理
  • 所有 API 统一管理

常见网关:

参考:网关的选择和使用

Nginx+Lua(OpenResty)、kong(基于OpenResty)、Zuul/Zuul2、Spring Cloud Gateway

(1)Kong 的性能非常不错,非常适合做流量网关,并且对于 service、route、upstream、consumer、plugins 的抽象,也是自研网关值得借鉴的。对于复杂系统,不建议业务网关用 Kong,或者更明确的说是不建议在 Java 技术栈的系统深度定制 Kong 或 OpenResty,主要是工程性方面的考虑。毕竟维护lua脚本的工作量和成本不低。

(2)pring Cloud Gateway/Zuul2 对于 Java 技术栈来说比较方便,可以依赖业务系统的一些 common jar。Lua 不方便,不光是语言的问题,更是复用基础设施的问题。另外,对于网关系统来说,性能不是差一个数量级,问题不大,多加 2 台机器就可以搞定。

(3)目前来看 Zuul2 的坑还是比较多的,因此作为java技术栈,比较建议使用 Spring Cloud Gateway 作为基础骨架。

介绍

Gateway是SpringCloud的一个全新项目,基于Spring5.0、Springboot2.0和Project Reactor等技术开发的网关,它旨在为微服务架构提供一种简单有效的统一的API路由管理方式。其作为SpringCloud生态系统中的网关,目标是替代Zuul,在SpringCloud2.0以上版本中,没有对新版本的Zuul2.0以上最新高性能版本进行集成,仍然还是使用的Zuul1.x非Reator模式的老版本。而为了提升网关的性能,Gateway是基于WebFlux框架实现的,二WebFlux框架底层则使用了高性能的Reactor模式通信框架Netty。

和zuul对比

  • Zuul 1.x 是阻塞式的高并发场景下效率低下
  • Gateway基于WebFlux是非阻塞式的异步框架
    • 引申:Spring WebFlux 是一个异步非阻塞式 IO 模型,通过少量的容器线程就可以支撑大量的并发访问。底层使用的是 Netty 容器,这点也和传统的 SpringMVC 不一样,SpringMVC 是基于 Servlet 的。
    • 使用参考:webflux使用

原理图:
在这里插入图片描述

gateway-client客户端
handler-mapping 根据断言匹配路由
web-handler 处理过滤器链
Filter在之前可以做参数校验、权限校验、流量监控、日志输出、协议转换等,在之后可以做响应内容&响应头的吸怪、日志的输出、流量监控等非常重要的作用。

核心概念

  • Route(路由):路由是构建网关的基本模块,它由ID,目标URI,一些列的断言和过滤器组成,如果断言为true则匹配改路由
  • Filter(过滤器):指的是GatewayFilter的实例,使用过滤器可以在请求被路由前或者后对请求进行修改
  • Filter(过滤器):指的是GatewayFilter的实例,使用过滤器可以在请求被路由前或者后对请求进行修改

Route主要配置项包括 :id、uri、 Predicates、path

  • id 路由的唯一标识,以服务名命名即可
  • uri 请求地址
  • predicates 主要起的作用是:基于Java8的Predicate,可以匹配Http请求中所有内容(例如请求头或者请求参数),如果请求与断言相匹配则进行路由
  • Path 配置对于请求路径的匹配规则,多个可用都好隔开、

++总结:条件predicates ,拦截filter,路由uri ++

路由:

cloud:
    nacos:
      discovery:
        server-addr: @env.cloud.nacos.server@
        namespace: @env.cloud.nacos.namespace@
        group: @env.cloud.nacos.group@
    gateway:
      discovery:
        locator:
          enabled: true
      routes:
        - id: steward
          uri: lb://steward
          predicates:
            - Path=/auth/**,/user/**

        - id: blog-sv
          uri: lb://blog-sv
          predicates:
            - Path=/user/**

过滤器的使用

  • 全局过滤器: GlobalFilter
    基于全局过滤可以实现对客户端请求的处理,比如添加用户信息,以方便下游使用当前登陆的用户关键信息。
@Component
@Slf4j
public class GlobalAuthenticationFilter implements GlobalFilter, Ordered {

    List<String> ignoreUrls= Arrays.asList();

    @Autowired
    private PemiFeignClient pemiFeignClient;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {

        String requestUrl = exchange.getRequest().getPath().value();
        log.info("请求地址:{}",requestUrl);
        Date start=new Date();
        //1、白名单放行
        if (checkUrls(ignoreUrls,requestUrl)){
            return chain.filter(exchange);
        }
        try {
            //调用认证服务查询或者校验用户信息
            AccountLoginInfoParam accountLoginInfoParam=new AccountLoginInfoParam();
            accountLoginInfoParam.setLoginName("17686486497");
            BaseResponse<Account> response=pemiFeignClient.getAccountByLoginName(accountLoginInfoParam);
            if (!response.isSuccess() || response.getData()==null){
                return invalidTokenMono(exchange);
            }
            response.getData();
            String userInfo=JSON.toJSONString(response.getData());
            log.info("当前用户信息:{}",userInfo);
            //设置用户信息
            String base64 = Base64.encode(userInfo);
            ServerHttpRequest tokenRequest = exchange.getRequest().mutate().header(TokenConstant.TOKEN_NAME, base64).build();
            ServerWebExchange exchangeWithUserInfo = exchange.mutate().request(tokenRequest).build();
            Date end=new Date();
            log.info("请求耗时:{}ms",end.getTime()-start.getTime());
            return chain.filter(exchangeWithUserInfo);
        }catch (Exception e){
            e.printStackTrace();
            return invalidTokenMono(exchange);
        }
    }

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

    /**
     * 对url进行校验匹配
     */
    private boolean checkUrls(List<String> urls,String path){
        AntPathMatcher pathMatcher = new AntPathMatcher();
        for (String url : urls) {
            if (pathMatcher.match(url,path))
                return true;
        }
        return false;
    }

    /**
     * 从请求头中获取Token
     */
    private String getToken(ServerWebExchange exchange) {
        String tokenStr = exchange.getRequest().getHeaders().getFirst("Authorization");
        if (StringUtils.isBlank(tokenStr)) {
            return null;
        }
        String token = tokenStr.split(" ")[1];
        if (StringUtils.isBlank(token)) {
            return null;
        }
        return token;
    }

    /**
     * 无效的token
     */
    private Mono<Void> invalidTokenMono(ServerWebExchange exchange) {
        return buildReturnMono(RespFactory.fail(ErrCodeEnum.INVALID_TOKEN.code,ErrCodeEnum.INVALID_TOKEN.getMsg()), exchange);
    }


    private Mono<Void> buildReturnMono(BaseResponse baseResponse, ServerWebExchange exchange) {
        ServerHttpResponse response = exchange.getResponse();
        byte[] bits = JSON.toJSONString(baseResponse).getBytes(StandardCharsets.UTF_8);
        DataBuffer buffer = response.bufferFactory().wrap(bits);
        response.setStatusCode(HttpStatus.UNAUTHORIZED);
        response.getHeaders().add("Content-Type", "application/json;charset:utf-8");
        return response.writeWith(Mono.just(buffer));
    }
}
遇到问题:

gateway中无法调用openfeign

Spring Cloud Gateway是基于WebFlux的,是ReactiveWeb,所以HttpMessageConverters不会自动注入,如HttpMessageConvertersAutoConfiguration源码所示。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-37a6i6lb-1656036962727)(https://img.october2.top/image.png1654594189305?e=1654597789&token=wSev1gzynuXgxcEYMfGcsli2c4R9hKbErgs0s-7Z:rrw-bOuhU6gDFgNY6MAJbt9UiSs=)]

解决方法

@SpringBootConfiguration
public class FeignConfig {

    @Bean
    @ConditionalOnMissingBean
    public HttpMessageConverters messageConverters(ObjectProvider<HttpMessageConverter<?>> converters) {
        return new HttpMessageConverters(converters.orderedStream().collect(Collectors.toList()));
    }

    @Bean
    public Decoder feignDecoder() {
        return new ResponseEntityDecoder(new SpringDecoder(feignHttpMessageConverter()));
    }

    public ObjectFactory<HttpMessageConverters> feignHttpMessageConverter() {
        final HttpMessageConverters httpMessageConverters = new HttpMessageConverters(new GateWayMappingJackson2HttpMessageConverter());
        return new ObjectFactory<HttpMessageConverters>() {
            @Override
            public HttpMessageConverters getObject() throws BeansException {
                return httpMessageConverters;
            }
        };
    }

    public static class GateWayMappingJackson2HttpMessageConverter extends MappingJackson2HttpMessageConverter {
        GateWayMappingJackson2HttpMessageConverter(){
            List<MediaType> mediaTypes = new ArrayList<>();
            mediaTypes.add(MediaType.valueOf(MediaType.TEXT_HTML_VALUE + "; charset=UTF-8"));
            setSupportedMediaTypes(mediaTypes);
        }
    }

}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值