zoukankan      html  css  js  c++  java
  • springcloud alibab-网关

    1.微服务容易出现的问题

    (1)客户端要维护服务端的各个地址,代码困难

    (2)认证,鉴权复杂

    (3)跨域问题

    2.为了解决上述问题,所以引入api网关,它的作用就是提供系统的统一入口,封装程序的内部结构,为客户端提供统一服务,一些与业务本身的功能的公共逻辑就可以在这里实现,例如:认证,鉴权,监控和路由转发

    3.流程

    (1)新建项目api-gateway

    (2)导入jar包

    <!--此模块不能引入web包-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-gateway</artifactId>
    </dependency>
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-alibaba-nacos-discovery</artifactId>
    </dependency>
    

    记住,千万不要导入web包,会冲突

    (3)在启动类上加入@EnableDiscoveryClient

    (4)修改配置文件

    spring:
      application:
        name: api-gateway
      cloud:
        nacos:
          discovery:
            server-addr: localhost:8848
        gateway:
          discovery:
            locator:
              enabled: true #可以让gateway发现nacos中的微服务
          routes:   #路由数组,就是指当前请求满足什么条件时转到哪个微服务
            - id: product_route #当前路由的标识,唯一
              #uri: http://localhost:8081  #请求要转发的地址
              uri: lb://service-product  #lb:负载均衡 后面跟着的是微服务的具体标识
              order: 1  #路由的优先级,数字越小级别越高
              predicates:   #断言,就是路由转发要满足的条件
                - Path=/product-serv/** #当请求路径满足Path指定的规则时,才能进行路由转发
              filters: #过滤器,请求在传递过程中可以通过过滤器对其进行一定的修改
                - StripPrefix=1 #转发之前去掉一层路径

    4.断言

    就是说在什么条件下才能执行真正的路由

    内置断言工厂

    (1)基于DateTime类型的断言工厂

    (2)基于远程地址的断言工厂

    (3)基于cookie的断言工厂

    (4)基于head的断言工厂

    (5)基于host的断言工厂

    (6)基于Methon请求方法的断言工厂

    (7)基于path请求路径的断言工厂

    (8)基于jquery请求参数的断言工厂

    (9)基于路由权重的断言工厂

    自定义断言工厂

    (1)在配置文件中添加断言配置 - Age=18,60

    (2)自定义断言工厂,实现断言方法

    import org.apache.commons.lang.StringUtils;
    import org.springframework.cloud.gateway.handler.predicate.AbstractRoutePredicateFactory;
    import org.springframework.stereotype.Component;
    import org.springframework.web.server.ServerWebExchange;
    
    import java.util.Arrays;
    import java.util.List;
    import java.util.function.Predicate;
    
    /**
     * 泛型,用于接收一个配置类,配置类用于接收配置文件中的配置
     */
    @Component
    public class AgeRoutePredicateFactory extends AbstractRoutePredicateFactory<AgeRoutePredicateFactory.Config> {
    
        public AgeRoutePredicateFactory() {
            super(AgeRoutePredicateFactory.Config.class);
        }
    
        /**
         * 用于配置文件中获取参数值赋值到配置类中到属性上
         * @return
         */
        @Override
        public List<String> shortcutFieldOrder() {
            //这里的配置要求和配置文件中的顺序一致
            return Arrays.asList("minAge", "maxAge");
        }
    
        @Override
        public Predicate<ServerWebExchange> apply(AgeRoutePredicateFactory.Config config) {
            return new Predicate<ServerWebExchange>() {
                //从serverWebExchange获取传入的参数
                @Override
                public boolean test(ServerWebExchange serverWebExchange) {
                    String ageStr = serverWebExchange.getRequest().getQueryParams().getFirst("age");
                    if (StringUtils.isNotEmpty(ageStr)) {
                        int age = Integer.parseInt(ageStr);
                        return age > config.getMinAge() && age < config.getMaxAge();
                    }
                    return true;
                }
            };
        }
    
        @Data
       public static class Config { 
        private Integer minAge;
        private Integer maxAge;
       }
    }

    5.过滤器

    作用:在请求的传递过程中,对请求和响应做一些手脚

    生命周期:Pre(身份认证,记录访问调试信息)和Post(添加请求头,收集统计信息和指标)

    分类:局部过滤器(作用在某一路由上)(GatewayFilter),全局过滤器(作用在全部路由上)(GlabolFilter)

    内置局部过滤器

    AddRequestHeader  为原始请求添加Header

    AddRequestParamter  为原始请求添加请求参数

    AddResponseHeader  为原始请求添加Header

    SetStatus  为原始请求添加状态码

    。。。

    自定义局部过滤器

    (1)修改配置文件

    - Log=true, false   #控制日志是否开启
    

    (2)自定义一个过滤工厂,实现方法

    import lombok.Data;
    import lombok.NoArgsConstructor;
    import org.springframework.cloud.gateway.filter.GatewayFilter;
    import org.springframework.cloud.gateway.filter.GatewayFilterChain;
    import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
    import org.springframework.stereotype.Component;
    import org.springframework.web.server.ServerWebExchange;
    import reactor.core.publisher.Mono;
    
    import java.util.Arrays;
    import java.util.List;
    
    /**
     * 自定义局部过滤器
     */
    @Component
    public class LogGatewayFilterFactory extends AbstractGatewayFilterFactory<LogGatewayFilterFactory.Config> {
    
        public LogGatewayFilterFactory() {
            super(LogGatewayFilterFactory.Config.class);
        }
    
        @Override
        public List<String> shortcutFieldOrder() {
            return Arrays.asList("consoleLog", "cacheLog");
        }
    
        @Override
        public GatewayFilter apply(LogGatewayFilterFactory.Config config) {
            return new GatewayFilter() {
                @Override
                public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
                    if(config.isCacheLog()) {
                        System.out.println("cache日志已开启");
                    }
                    if(config.isConsoleLog()) {
                        System.out.println("console日志已开启");
                    }
                    return chain.filter(exchange);
                }
            };
        }
    
        /**
         * 自定义内部类,用来接收参数
         */
        @Data
        @NoArgsConstructor
        public class Config{
    
            private boolean consoleLog;
    
            private boolean cacheLog;
        }
    }
    

    全局过滤器

    内置全局过滤器

    无需配置

    uri: lb://service-product  #lb:负载均衡 后面跟着的是微服务的具体标识
    

    这就是一个全局过滤器

    自定义全局过滤器

    鉴权

    /**
     * 自定义全局过滤器(统一鉴权)
     */
    @Slf4j
    @Component
    public class AuthGlobalFilter implements GlobalFilter, Ordered {
    
        /**
         * 用于编写过滤器的逻辑
         * @param exchange
         * @param chain
         * @return
         */
        @Override
        public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
            String token = exchange.getRequest().getQueryParams().getFirst("token");
            if (!StringUtils.equals("admin",token)){
                //认证失败
                log.info("认证失败了。。。");
                exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
                return exchange.getResponse().setComplete();
            }
            return chain.filter(exchange);
        }
    
        /**
         * 用来标识当前过滤器的优先级
         * @return
         */
        @Override
        public int getOrder() {
            return 0;
        }
    }
    

    6.网关限流

    (1)基于路由维度的限流(在配置文件中配置的路由条目,资源名为对应的routeId)

    导入依赖

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

    编写配置类

    import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayFlowRule;
    import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayRuleManager;
    import com.alibaba.csp.sentinel.adapter.gateway.sc.SentinelGatewayFilter;
    import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.BlockRequestHandler;
    import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.GatewayCallbackManager;
    import com.alibaba.csp.sentinel.adapter.gateway.sc.exception.SentinelGatewayBlockExceptionHandler;
    import org.springframework.cloud.gateway.filter.GlobalFilter;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.core.Ordered;
    import org.springframework.core.annotation.Order;
    import org.springframework.http.HttpStatus;
    import org.springframework.http.MediaType;
    import org.springframework.http.codec.ServerCodecConfigurer;
    import org.springframework.web.reactive.function.BodyInserters;
    import org.springframework.web.reactive.function.server.ServerResponse;
    import org.springframework.web.reactive.result.view.ViewResolver;
    import org.springframework.web.server.ServerWebExchange;
    import reactor.core.publisher.Mono;
    
    import javax.annotation.PostConstruct;
    import java.util.*;
    
    @Configuration
    public class GatewayConfiguration {
    
        private final List<ViewResolver> viewResolvers;
    
        private final ServerCodecConfigurer serverCodecConfigurer;
    
        public GatewayConfiguration(List<ViewResolver> viewResolvers, ServerCodecConfigurer serverCodecConfigurer) {
            this.viewResolvers = viewResolvers;
            this.serverCodecConfigurer = serverCodecConfigurer;
        }
    
        /**
         * 初始化一个限流过滤器
         * @return
         */
        @Bean
        @Order(Ordered.HIGHEST_PRECEDENCE)
        public GlobalFilter sentinelGatewayFilter() {
            return new SentinelGatewayFilter();
        }
    
        @PostConstruct
        public void initGatewayRules() {
            Set<GatewayFlowRule> rules = new HashSet<>();
            rules.add(new GatewayFlowRule("product-rule")   //资源名称,对应的路由id
                    .setCount(1)        //限流阈值
                    .setIntervalSec(1));    //统计时间窗口
            GatewayRuleManager.loadRules(rules);
        }
    
        /**
         * 配置限流的异常处理器
         * @return
         */
        @Bean
        @Order(Ordered.HIGHEST_PRECEDENCE)
        public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() {
            return new SentinelGatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer);
        }
    
        @PostConstruct
        public void initBlockHandlers() {
            BlockRequestHandler blockRequestHandler = new BlockRequestHandler() {
                @Override
                public Mono<ServerResponse> handleRequest(ServerWebExchange serverWebExchange, Throwable throwable) {
                    Map map = new HashMap();
                    map.put("code", 0);
                    map.put("message", "接口被限流了");
                    return ServerResponse.status(HttpStatus.OK).contentType(MediaType.APPLICATION_JSON_UTF8)
                            .body(BodyInserters.fromObject(map));
                }
            };
            GatewayCallbackManager.setBlockHandler(blockRequestHandler);
        }
    }

    (2)自定义api维度(用户可以用sentinel提供的api来自定义一些api分组)

        @PostConstruct
        public void initGatewayRules() {
            Set<GatewayFlowRule> rules = new HashSet<>();
            rules.add(new GatewayFlowRule("product_api1").setCount(1).setIntervalSec(1));
            rules.add(new GatewayFlowRule("product_api2").setCount(1).setIntervalSec(1));
            GatewayRuleManager.loadRules(rules);
        }
    
        /**
         * 自定义api分组
         */
        @PostConstruct
        private void initCustomizedApis() {
            Set<ApiDefinition> definitions = new HashSet<>();
            ApiDefinition apiDefinition1 = new ApiDefinition("product_api")
                    .setPredicateItems(new HashSet<ApiPredicateItem>(){{
                        //以/product-serv/product/api1开头的请求
                        add(new ApiPathPredicateItem().setPattern("/product-serv/product/api1/**")
                        .setMatchStrategy(SentinelGatewayConstants.URL_MATCH_STRATEGY_PREFIX));
                    }});
            ApiDefinition apiDefinition2 = new ApiDefinition("product_api2")
                    .setPredicateItems(new HashSet<ApiPredicateItem>(){{
                        //以/product-serv/product/api2/demo1 完整的url路径匹配
                        add(new ApiPathPredicateItem().setPattern("/product-serv/product/api2/demo1")
                        .setMatchStrategy(SentinelGatewayConstants.URL_MATCH_STRATEGY_PREFIX));
                    }});
            definitions.add(apiDefinition1);
            definitions.add(apiDefinition2);
            GatewayApiDefinitionManager.loadApiDefinitions(definitions);
        }
    

      

  • 相关阅读:
    SpringFramework|@Autowired
    SpringFramework|@Required的使用
    SpringFramework|基于XML的两种自动装配
    SpringFramework|基于XML的各类集合注入
    SpringFramework|基于XML的依赖注入
    erlang vim
    svn 强制输入提交日志
    vim配置
    克隆centos6后配置网络
    git 免密
  • 原文地址:https://www.cnblogs.com/freeht/p/12933703.html
Copyright © 2011-2022 走看看