开发公司【云原生】springcloud12——服务网关Gateway

前 言
🍉 作者简介:半旧518,开发公司长跑型选手,开发公司立志坚持写10年博客,专注于java后端
☕专栏简介:深入、全面、开发公司系统的介绍springcloud与springcloud Alibaba开发公司微服务常用技术栈
🌰 文章简介:开发公司本文将介绍HyStrix服务熔断、降级,开发公司建议收藏备用,创作不易,开发公司敬请三连哦
🥒文章推荐:










文章目录

1 GateWay简介

1.1 Zuul开发公司退出历史舞台

第一代是zuul,zuul开发公司核心人员走了两个,zuul2开发公司的核心开发人员分歧较大,研发过久,spring开发公司公司等不及,开发公司自己研发的Gateway网关。

1.2 GateWay是什么

官网文档:https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.2.1.RELEASE/reference/html/



开发公司在微服务架构中网关的开发公司位置可以参考下图,开发公司也就是说网关是微服务开发公司最外面的入口,开发公司挡在第一线。

1.3 Gateway的特点

1.4 Zuul与Gateway的对比

1.5 Gateway开发公司的非阻塞异步模型



而springcloud Gateway使用了spring5的新特性:webflux和reactive stack


2 Hello Gateway

2.1 Gateway开发公司的工作流程

开发公司先讲解三个核心概念。

Route(路由):开发公司路由是构建网关的基本模块,它由ID,目标URL,开发公司一系列的断言和过滤器组成,如断言为true开发公司则匹配路由。

(断言):断言是JDK8的新特性,可以参考java.util.function.Predicate。断言是编程术语,表示为一些布尔表达式,程序员相信在程序中的某个特定点该表达式值为真,可以在任何时候启用和禁用断言验证,因此可以在测试时启用断言而在部署时禁用断言。同样,程序投入运行后,最终用户在遇到问题时可以重新启用断言。开发人员可以匹配HTTP请求中的所有内容(例如请求头或请求参数),如果请求与断言相匹配则进行路由。

Filter(过滤):指的是Spring框架中GatewayFilter的实例,使用过滤器,可以在请求被路由前或之后对请求进行修改。

Gateway的工作流程可以参考下图。

web请求,通过一些匹配条件,定位到真正的服务节点,并在这个转发过程的前后,进行精细化的控制。Predicate就是我们匹配的条件,而Filter,可以理解为一个无所不能的拦截器,再加上目标URI,就可以实现一个具体的路由了

官网对于GateWay也进行了相应的总结。


2.2 搭建网关

(1)建模块
cloud-gateway-gateway9527

(2)写pom
注意:gateway 是网关,不是web项目,不能带spring-boot-starter-web,否则后面启动服务会出错哟。

 <dependencies>        <!--gateway-->        <dependency>            <groupId>org.springframework.cloud</groupId>            <artifactId>spring-cloud-starter-gateway</artifactId>        </dependency>        <!-- 引用自己定义的api通用包,可以使用Payment支付Entity -->        <dependency>            <groupId>com.wangzhou.springcloud</groupId>            <artifactId>cloud-api-commons</artifactId>            <version>${project.version}</version>        </dependency>        <!--eureka client(通过微服务名实现动态路由)-->        <dependency>            <groupId>org.springframework.cloud</groupId>            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>        </dependency>        <!--热部署-->        <dependency>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-devtools</artifactId>            <scope>runtime</scope>            <optional>true</optional>        </dependency>        <dependency>            <groupId>org.projectlombok</groupId>            <artifactId>lombok</artifactId>            <optional>true</optional>        </dependency>        <dependency>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-starter-test</artifactId>            <scope>test</scope>        </dependency>    </dependencies>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

(3)写yml

server:  port: 9527spring:  application:    name: cloud-gatewayeureka:  instance:    hostname: cloud-gateway-service  client:    fetch-registry: true    register-with-eureka: true    service-url:      #单机版      defaultZone: http://localhost:7001/eureka      #集群版#      defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka,http://eureka7003.com:7003/eureka
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

(4)主启动

@SpringBootApplication@EnableEurekaClient //9527自己也是微服务,要向注册中心注册哟public class GatewayMain9527 {    public static void main(String[] args) {        SpringApplication.run(GatewayMain9527.class, args);    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

(5)网关配置
回顾下我们之前的8001支付微服务,对外暴露了下面两个接口:/payment/get/{id},/payment/lb,如果我们不想将这两个接口直接暴露给外接,而希望网关9527在外面挡一层,可以修改下9527的yml文件。

server:  port: 9527spring:  application:    name: cloud-gateway  cloud:    gateway:      routes:        - id: payment_route # 路由的id,没有规定规则但要求唯一,建议配合服务名          #匹配后提供服务的路由地址          uri: http://localhost:8001          predicates:            - Path=/payment/get/** # 断言,路径相匹配的进行路由        - id: payment_route2          uri: http://localhost:8001          predicates:            - Path=/payment/lb/** #断言,路径相匹配的进行路由eureka:  instance:    hostname: cloud-gateway-service  client:    fetch-registry: true    register-with-eureka: true    service-url:      defaultZone: http://eureka7001.com:7001/eureka/
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

2.3测试

依次启动7001,8001,9527三个微服务

访问:http://localhost:9527/payment/get/1
再来。使用原端口

也可以访问,我们渐渐淡化了真实地址,通过网关端口访问

如果想安全点,服务器设置防火墙把8001墙了,只开放网关端口就好啦呀

回顾下网关的对应关系。

访问下lb:http://localhost:9527/payment/lb

发现没有,访问9527端口实际上找到的还是8001.

3 网关的路由配置

3.1 Gateway的网关路由配置的两种方式

(1)在配置文件中配置
在配置文件yml中配置(参考上面yml文件配置)

(2)在配置类中配置
代码中注入RouteLocator的Bean(下面通过编码进ioc容器中配置)


来操作下。
新建config.GatewayConfig

@Configurationpublic class GatewayConfig {    @Bean    public RouteLocator CustomRouteLocator(RouteLocatorBuilder routeLocatorBuilder){        RouteLocatorBuilder.Builder routes = routeLocatorBuilder.routes();        routes.route("path_route_banjiu"                ,r -> r.path("/guonei")                        .uri("http://news.baidu.com/guonei"))                .build();                //现在访问localhost:9527/guonei 会被转发到 http://news.baidu.com/guonei        return routes.build();    }        @Bean    public RouteLocator CustomRouteLocator2(RouteLocatorBuilder routeLocatorBuilder){        RouteLocatorBuilder.Builder routes = routeLocatorBuilder.routes();                routes.route("path_route_banjiu"                ,r -> r.path("/guoji")                        .uri("http://news.baidu.com/guoji"))                .build();        //现在访问localhost:9527/guonei 会被转发到 http://news.baidu.com/guoji        return routes.build();    }}// 测试结果:buld可以不加
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

启动9527,测试下。访问:http://localhost:9527/guonei

3.2 动态路由配置

我们上面的两种路由配置都有一个问题,就是地址被写成了hard code,我们这里只使用8001当然好像没问题,那我们要是使用集群呢?要是扩容呢?

先回顾下我们最初的技术架构:使用ribbon实现负载均衡。

当我们有了网关以后,8001,8002就不再直接暴露给外部了,那由网关负责负载均衡就好了,下面是2.0版本。

下面实战下。
(1)先启动7001,8001,8002
(2)配置动态路由
将9527的yml文件进行如下修改。

server:  port: 9527spring:  application:    name: cloud-gateway  cloud:    gateway:      discovery:        locator:          enabled: true  #开启从注册中心动态创建路由的功能,利用微服务名称进行路由(默认false)      routes:        - id: payment_route # 路由的id,没有规定规则但要求唯一,建议配合服务名          #匹配后提供服务的路由地址          #          uri: http://localhost:8001          uri: lb://cloud-payment-service # lb代表从注册中心获取服务          predicates:            - Path=/payment/get/** # 断言,路径相匹配的进行路由        - id: payment_route2          #          uri: http://localhost:8001          uri: lb://cloud-payment-service          predicates:            - Path=/payment/lb/** #断言,路径相匹配的进行路由eureka:  instance:    hostname: cloud-gateway-service  client:    fetch-registry: true    register-with-eureka: true    service-url:      defaultZone: http://eureka7001.com:7001/eureka/
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

(3)测试
启动9527,访问http://localhost:9527/payment/lb
可以看到8001,8002轮流返回。

4 Predicate的使用

4.1 Predicate是什么

我们可以在9527启动日志中看到如下日志消息。

Predicate究竟是什么东东,有哪些Predicate可以配置呢?

我们先看看官网怎么说。


翻译下

通俗浅显的理解就是,这是一个匹配条件。

4.2 Gateway常用的Predicate

先来捞一眼。


我们简单介绍几种,需要使用时对着官方文档查阅即可。

4.3 After/Before/Between Route Predicate

先看三个和时间相关的Predicate

看官网的例子,知道我们需要配置如下格式的时间使用,但是它使用的是美国的时间,那么其它地区这个时间如何得到呢?


新建测试类T2

public class T2 {    public static void main(String[] args) {        ZonedDateTime now = ZonedDateTime.now();        System.out.println(now);    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

结果如下。

把这个串串复制下,根据自己的需要推算下时间,改下就可以生效。

比如将After设置为还没有到来的时间,就会无法访问lb接口了,只有时间到了才能访问。

至于Before,Between就很雷同,不解释了。

这有啥用呢?打个比方,比如你的项目提前上线了,但是某个接口你希望到某个时间才开始生效,就可以设置这个断言了。

4.4 Cookie Route Predicate

它表示是否需要带cookie访问,可以配置需要的cookie作为断言。

配置下。

打开cmd终端,输入curl http://localhost:9527/payment/lb(直接访问失败,看404的状态就可以了)

带cookie访问:输入curl http://localhost:9527/payment/lb --cookie “username=banjiu”

4.5 Header

指定访问需要带的请求头。

配一下.

 #请求头要有 X-Request-Id属性并且值为整数的正则表达式- Header=X-Request-Id, \d+  
  • 1
  • 2

测试。

5 Gateway的Filter

使用过滤器,可以在请求前或者请求后对其进行修改。

springcloud自带的过滤器有很多,看看官网的注释就会用了,接下来讲下自定义过滤器。我们在实际生产中,用得更多的也是自定义的过滤条件。

新建filter.MyLogGateWayFilter

@Component@Slf4j//@Order(0)   //设置过滤器优先次序public class MyLogGateWayFilter implements GlobalFilter, Ordered {//Ordered优先次序设置;GlobalFilter过滤器设置    @Override    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {        log.info("**************come in MyLogGateWayFilter:" + new Date());        //获取request中的uname参数        String uname = exchange.getRequest().getQueryParams().getFirst("uname");        if(uname == null){            log.info("*******用户名为null,非法用户!!");            //设置响应,不被接受            exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);            return exchange.getResponse().setComplete();        }        //返回chain.filter(exchange),放行        return chain.filter(exchange);    }    @Override    public int getOrder() {        //返回值是过滤器的优先级,越小优先级越高(最小-2147483648,最大2147483648)        return 0;    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

测试下,启动7001,8001,8002,9527(记得把之前断言不需要的注释哦).

http://localhost:9527/payment/lb?uname=111

网站建设定制开发 软件系统开发定制 定制软件开发 软件开发定制 定制app开发 app开发定制 app开发定制公司 电商商城定制开发 定制小程序开发 定制开发小程序 客户管理系统开发定制 定制网站 定制开发 crm开发定制 开发公司 小程序开发定制 定制软件 收款定制开发 企业网站定制开发 定制化开发 android系统定制开发 定制小程序开发费用 定制设计 专注app软件定制开发 软件开发定制定制 知名网站建设定制 软件定制开发供应商 应用系统定制开发 软件系统定制开发 企业管理系统定制开发 系统定制开发