SpringCloudAlibaba基础学习--Gateway网关

  • 什么是网关 
     
           网关是整个微服务API请求的入口,负责拦截所有请求,分发到服务上去。可以实现日志拦截、权限控制、解决跨域问题、限流、熔断、负载均衡、黑名单与白名单拦截、授权等
      
  • 过滤器与网关的区别
     
    网关是拦截所有服务器请求进行控制
    过滤器拦截某单个服务器请求进行控制
  • Zuul与Gateway有那些区别
     
     Zuul网关属于netfix公司开源的产品属于第一代微服务网关,是基于Servlet实现的,阻塞式的Api, 不支持长连接。
    Gateway属于SpringCloud研发的第二代微服务网关,是基于Spring5构建,能够实现响应式非阻塞式的Api,支持长连接。 
     
    相比来说SpringCloudGateway性能比Zuul性能要好,Zuul是基于Servlet实现, gateway基于netty实现
  • 网关与nginx区别 
      
    相同点:都是可以实现对api接口的拦截,负载均衡、反向代理、请求过滤等,可以实现和网关一样的效果。
    不同点:Nginx采用C语言编写,Gateway属于Java语言编写的, 能够更好让我们使用java语言来实现对请求的处理。
     
    Nginx 属于服务器端负载均衡器。
    Gateway 属于本地负载均衡器。 
     
  • Gateway执行流程
  1.  流程
    Spring Cloudç½å³å¾ 
    a. 客户端发送请求,会到达网关的DispatcherHandler处理,匹配到RoutePredicateHandlerMapping。
    b. 根据RoutePredicateHandlerMapping匹配到具体的路由策略。
    c. FilteringWebHandler获取的路由的GatewayFilter数组,创建 GatewayFilterChain 处理过滤请求
    d. 执行我们的代理业务逻辑访问。
  2.  Gateway常见路由策略
     Spring Cloud Gateway

  • 项目集成gateway
     
  1. 创建会员项目 
    项目创建参考:  SpringCloudAlibaba基础学习--nacos服务注册与发现_xiaobo5264063的博客-CSDN博客
    将会员服务注册到nacos, 服务名称为:  pitch-member 
    提供会员服务集群地址:  http://127.0.0.1:9001/obtain
                                           http://127.0.0.1:9002/obtain
     
  2. 创建网关项目
    在pom.xml引入依赖 
     <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.0.5.RELEASE</version>
            <relativePath/> <!-- lookup parent from repository -->
        </parent>
    
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-gateway</artifactId>
                <version>2.0.0.RELEASE</version>
            </dependency>
            <!-- nacos整合服务注册与发现-->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
                <version>0.2.2.RELEASE</version>
            </dependency>
        </dependencies>
    SpringCloud gateway基于webflux实现的,不是基于SpringBoot-web,所以应该删除spring-boot-starter-web依赖 
     
    application.yml配置  
    server:
      port: 80
    ####服务网关名称
    spring:
      application:
        name: pitch-gateway
      cloud:
        gateway:
          discovery:
            locator:
              ####允许从注册中心获取地址
              enabled: true
          routes:
            ###路由id  自定义唯一
            - id: pitch
              ####pitch-member为会员服务的名称
              uri: lb://pitch-member/
              filters:
                - StripPrefix=1
              ###路由匹配规则 表示当客户端访问http://ip:80/member/**地址时, gateway就会转发到pitch-member会员服务的具体地址
              predicates:
                - Path=/member/**
        nacos:
          discovery:
            ###将网关服务注册到nacos
            server-addr: 127.0.0.1:8848
            enabled: true
     常见路由策略:   Spring Cloud Gateway
     
  3. 网关服务启动类
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    
    
    @SpringBootApplication
    public class AppGateway {
        public static void main( String[] args ) {
            SpringApplication.run(AppGateway.class);
        }
    }
    
     
  4. 测试 
    网关地址  http://127.0.0.1/member/obtain
      
     
     如图所示:当我们访问网关地址时,gateway会转发到具体的服务地址,并默认实现负载均衡。
  5.  实现自定义参数拦截
    import org.apache.commons.lang3.StringUtils;
    import org.springframework.cloud.gateway.filter.GatewayFilterChain;
    import org.springframework.cloud.gateway.filter.GlobalFilter;
    import org.springframework.core.io.buffer.DataBuffer;
    import org.springframework.http.HttpStatus;
    import org.springframework.http.server.reactive.ServerHttpResponse;
    import org.springframework.stereotype.Component;
    import org.springframework.web.server.ServerWebExchange;
    import reactor.core.publisher.Mono;
    
    /**
     * @author xiaobo
     * @Description MyFilter
     * @createTime 2020-03-30 20:20
     */
    @Component
    public class MyFilter  implements GlobalFilter {
    
        @Override
        public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
            // 获取token
            String token = exchange.getRequest().getQueryParams().getFirst("token");
            // 判断的token是否为空
            if (StringUtils.isEmpty(token)) {
                ServerHttpResponse response = exchange.getResponse();
                response.setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR);
                String msg = "token not is null ";
                DataBuffer buffer = response.bufferFactory().wrap(msg.getBytes());
                return response.writeWith(Mono.just(buffer));
            }
            // 直接转发到我们真实服务
            return chain.filter(exchange);
        }
    
    }
    通过网关判断的请求是否有token
     
  6.  测试
     http://127.0.0.1/member/obtain?token=123   此时转发真实地址
     http://127.0.0.1/member/obtain                       提示token is null
     
      
  • 使用全局过滤器解决跨域问题
    import org.springframework.cloud.gateway.filter.GatewayFilterChain;
    import org.springframework.cloud.gateway.filter.GlobalFilter;
    import org.springframework.http.HttpHeaders;
    import org.springframework.http.server.reactive.ServerHttpRequest;
    import org.springframework.http.server.reactive.ServerHttpResponse;
    import org.springframework.stereotype.Component;
    import org.springframework.web.server.ServerWebExchange;
    import reactor.core.publisher.Mono;
    
    @Component
    public class CrossOriginFilter implements GlobalFilter {
        @Override
        public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
    
            // 允许跨域请求
            ServerHttpRequest request = exchange.getRequest();
            ServerHttpResponse response = exchange.getResponse();
            HttpHeaders headers = response.getHeaders();
            headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, "*");
            headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, "POST, GET, PUT, OPTIONS, DELETE, PATCH");
            headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS, "true");
            headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS, "*");
            headers.add(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, "*");
            return chain.filter(exchange);
    
        }
    }

  • 基于数据库形式实现动态网关配置
     
     
  1.  基于上面个的项目
     注释掉application.yml中gateway转发的配置
    server:
      port: 80
    ####服务网关名称
    spring:
      application:
        name: pitch-gateway
      cloud:
        gateway:
          discovery:
            locator:
              ####允许从注册中心获取地址
              enabled: true
        nacos:
          discovery:
            ###将网关服务注册到nacos
            server-addr: 127.0.0.1:8848
            enabled: true

  2.  转发服务
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.cloud.gateway.event.RefreshRoutesEvent;
    import org.springframework.cloud.gateway.filter.FilterDefinition;
    import org.springframework.cloud.gateway.handler.predicate.PredicateDefinition;
    import org.springframework.cloud.gateway.route.RouteDefinition;
    import org.springframework.cloud.gateway.route.RouteDefinitionWriter;
    import org.springframework.context.ApplicationEventPublisher;
    import org.springframework.context.ApplicationEventPublisherAware;
    import org.springframework.stereotype.Service;
    import org.springframework.web.util.UriComponentsBuilder;
    import reactor.core.publisher.Mono;
    import java.net.URI;
    import java.util.Arrays;
    import java.util.Map;
    import java.util.HashMap;
    /**
     * @author xiaobo
     * @Description GatewayService
     * @createTime 2020-03-30 21:27
     */
    @Service
    public class GatewayService  implements ApplicationEventPublisherAware {
    
        private ApplicationEventPublisher publisher;
        @Autowired
        private RouteDefinitionWriter routeDefinitionWriter;
    
        @Override
        public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
            this.publisher = applicationEventPublisher;
        }
        
        // 路由id  转发的注册中的服务   客户端的访问地址   
        // 表示当客户端访问gateway的url地址时,gateway就是转发到serverName的真实服务中
        public String updateRoute(String id, String serverName, String url) {
            RouteDefinition definition = new RouteDefinition();
            Map<String, String> predicateParams = new HashMap<>(8);
            PredicateDefinition predicate = new PredicateDefinition();
            FilterDefinition filterDefinition = new FilterDefinition();
            Map<String, String> filterParams = new HashMap<>(8);
            // fromUriString表示以注册中心服务名作为地址
            URI uri = UriComponentsBuilder.fromUriString("lb://" + serverName + "/").build().toUri();
            // fromHttpUrl表示以http形式转发地址
            // URI uri = UriComponentsBuilder.fromHttpUrl("http://www.baidu.com").build().toUri();
            // 定义的路由唯一的id
            definition.setId(id);
            predicate.setName("Path");
            //路由转发地址
            predicateParams.put("pattern", url);
            predicate.setArgs(predicateParams);
    
            // 名称是固定的, 路径去前缀
            filterDefinition.setName("StripPrefix");
            filterParams.put("_genkey_0", "1");
            filterDefinition.setArgs(filterParams);
            definition.setPredicates(Arrays.asList(predicate));
            definition.setFilters(Arrays.asList(filterDefinition));
            definition.setUri(uri);
            routeDefinitionWriter.save(Mono.just(definition)).subscribe();
            this.publisher.publishEvent(new RefreshRoutesEvent(this));
            return "success";
        }
    }
  3.  提供刷新接口
     
    import com.pitch.service.GatewayService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    /**
     * @author xiaobo
     * @Description UpdateGatewayController
     * @createTime 2020-03-30 21:57
     */
    @RestController
    public class UpdateGatewayController {
    
        @Autowired
        private GatewayService gatewayService;
    
        @GetMapping("/update")
        public String update(){
            // 路由id
            String id = "myId";
            // 会员服务
            String serverName = "pitch-member";
            // 转发地址
            String url = "/member/**";
            // 这里可以改为从数据库获取
            gatewayService.updateRoute(id, serverName, url);
            return "success";
        }
    }
    这里需要改成从数据库获取
      
  4.  启动测试
     访问:  http://127.0.0.1/member/obtain?token=123  此时应该404
     访问:  http://127.0.0.1/update            gateway加载转发地址
     http://127.0.0.1/member/obtain?token=123
      
     
  •  基于keepalived+nginx实现gataway高可用
     
  1.  原理
     
      

      
     
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值