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);
        }
    

      

  • 相关阅读:
    Chrome cookies folder
    Fat URLs Client Identification
    User Login Client Identification
    Client IP Address Client Identification
    HTTP Headers Client Identification
    The Personal Touch Client Identification 个性化接触 客户识别
    购物车 cookie session
    购物车删除商品,总价变化 innerHTML = ''并没有删除节点,内容仍存在
    453
    购物车-删除单行商品-HTMLTableElement.deleteRow()
  • 原文地址:https://www.cnblogs.com/freeht/p/12933703.html
Copyright © 2011-2022 走看看