【Spring Cloud Alibaba 微服务原理与实战系列七】

1 网关介绍

在微服务架构中,顾名思义,一个大的系统会被拆分成多个小的服务,如果没有网关的存在,发请求的时候,客户端只能记录每个服务的地址和端口,然后分别去调用
在这里插入图片描述
很显然你在访问淘宝的时候,他所有的前缀都是淘宝自己的域名,不可能说去购物车是一个ip,去订单是一个ip。这就是用网关实现的,那网关具体能做什么呢

  • 客户端发请求只会发送给网关,网关统一转发,对外暴露的ip只会有一个
  • 网关可以实现认证,只需要一次认证,不然的话,进入每个服务都需要认证一次
  • 解决跨域,服务间调用时候可能存在跨域问题,网关能实现

在这里插入图片描述
整体架构就会变成如下
在这里插入图片描述

2.简介

spring公司基于5.0版本,Spring Boot2.0等技术开发的网关,目的就是为了为微服务架构中提供一种简单,有效,统一的API路由管理方式,目标是为了取代netflfiix Zuul,基于Filter链的方式提供网关的基本功能,例如:安全,监控,限流
优点:

  • 性能强:相比zuul快很多
  • 功能强:内置了很多功能,限流,转发,监控等
  • 设计强:容易拓展

缺点:

  • 实现依赖于Netty和Webful,学习成本较高
  • 不支持部署在常规容器中,比如tomcat,只能打包成jar
  • Spring Boot2.0以上版本才支持

3 创建一个网关模块,并且导入依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>server-parent</artifactId>
        <groupId>com.threesum</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>server-gateway</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
    </dependencies>
</project>

3.1 实现网关转发(基础版本)

3.1.1编写配置文件

server:
  port: 7000
spring:
  application:
    name: server-gateway #服务名
  devtools:
    restart:
      enabled: true #是否支持热部署
  cloud:
    gateway:
      routes: #路由数组
        - id: product_route #路由的ID(类似mysql主键ID),有固定规则但要求唯一,建议配合服务名
          uri: http://localhost:8002  #这里写死,请求转发到的地址
          #uri: lb://server-product #lb指的是从nacos中获取服务的名字,并且遵守负载均衡策略
          order: 1 #路由的优先级,数字越小优先级越高
          predicates: # 断言(转发的时候需要满足哪些条件才转发到这个路由)
            - Path=/service/**
          filters:  # 过滤器,请求在传递过程中可以通过过滤器对其进行一定的修改
            - StripPrefix=1  # 转发之前去掉1层路径,数字表示要截断的路径的数量,因为上面配置的是满足前缀是/service,所以转发要直接把这个service去除

3.1.2调用测试

原本商品服务直接访问接口:http://localhost:8002/product/1
在这里插入图片描述
使用网关转发:http://localhost:7000/service/product/1
在这里插入图片描述

3.2 使用nacos实现(增强版本)

3.2.1加入nacos依赖

 <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>

3.2.2在主启动类上加上启动nacos客户端

@SpringBootApplication
@EnableDiscoveryClient
public class GateWayApplication {

    public static void main(String[] args) {
        SpringApplication.run(GateWayApplication.class, args);
    }
}

3.2.3修改配置文件

server:
  port: 7000

spring:
  application:
    name: server-gateway #服务名

  devtools:
    restart:
      enabled: true #是否支持热部署
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
    gateway:
      discovery:
        locator:
          enabled: true #让网关可以发现nacos中的服务
      routes: #路由数组
        - id: product_route #路由的ID(类似mysql主键ID),有固定规则但要求唯一,建议配合服务名
          #uri: http://localhost:8002  #这里写死,请求转发到的地址
          uri: lb://server-product #lb指的是从nacos中获取服务的名字,并且遵守负载均衡策略
          order: 1 #路由的优先级,数字越小优先级越高
          predicates: # 断言(转发的时候需要满足哪些条件才转发到这个路由)
            - Path=/service/**
          filters:  # 过滤器,请求在传递过程中可以通过过滤器对其进行一定的修改
            - StripPrefix=1  # 转发之前去掉1层路径  数字表示要截断的路径的数量,因为上面配置的是满足前缀是/service,所以转发要直接把这个service去除

在这里插入图片描述

3.2.4测试

在这里插入图片描述

4 断言

Predicate(断言),用于进行条件判断的,当断言结果返回真,才会执行路由,直白的说就是,在什么条件下才进行路由转发

4.1内置路由断言工厂

断言工厂作用示例
AfterRoutePredicateFactory接收一个日期参数,判断请求的日期是否晚于指定日期-After=2019-12-31T23:59:59,789+08:00[Asia/Shanghai]
BeforeRoutePredicateFactory接收一个日期参数,判断请求的日期是否早于指定日期-After=2019-12-31T23:59:59,789+08:00[Asia/Shanghai]
BetweenRoutePredicateFactory接收两个日期参数,判断请求的日期是否在指定日期内-Betweenr=2019-12-31T23:59:59,789+08:00[Asia/Shanghai],2021-12-31T23:59:59,789+08:00[Asia/Shanghai]
RemoteAddrRoutePredicateFactory接收一个ip的地址段,判断参数是否在指定的地址段内部-RemoteAddr=192.168.1.1/24
CookieRoutePredicateFactory接收两个参数-Cookie=chocolate,ch.
HeaderRoutePredicateFactony接收两个参数,标题名称和正则表达式。判断请求Header是否具有给定名称且值与正则表达式匹配-Header=X-Request-ld, \d+
HostRoutePredicateFactory接收一个参数,主机名模式。判断请求的Host是否满足匹配规则-Host=**.testhost.org
MethodRoutePredicateFactory接收一个参数,判断请求类型是否跟指定的类型匹配-Method=GET
PathRoutePredicateFactory接收一个参数,判断请求的URI部分是否满足路径规则-Path=/foo/{segment}
QueryRoutePredicateFactory接收两个参数,请求param和正则表达式,判断请求参数是否具有给定名称且值与正则表达式匹配-Query-baz, ba.
WeightRoutePredicateFactory收一个[组名,权重],然后对于同一个组内的路由按照权重转发

4.2自定义路由断言工厂

设置一个场景,我们的接口只能让当前的登录用户年纪为18-20岁之间的人访问

4.2.1配置文件中,添加一个Age的断言

在这里插入图片描述

4.2.2自定义一个断言工厂,实现断言方法

package com.threesum.predicates;

import org.springframework.cloud.gateway.handler.predicate.AbstractRoutePredicateFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;


import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;


@Component
public class AgeRoutePredicatesFactory extends AbstractRoutePredicateFactory<AgeRoutePredicatesFactory.Config> {


    public AgeRoutePredicatesFactory() {
        super(AgeRoutePredicatesFactory.Config.class);
    }

    public List<String> shortcutFieldOrder(){
        //这里的顺序要跟配置文件中的参数顺序一样
        return Arrays.asList("minAge","maxAge");
    }

    @Override
    public Predicate<ServerWebExchange> apply(Config config) {
        return new Predicate<ServerWebExchange>() {
            @Override
            public boolean test(ServerWebExchange serverWebExchange) {
                //获取参数
                String ageStr=serverWebExchange.getRequest().getQueryParams().getFirst("age");
                if(!StringUtils.isEmpty(ageStr)){
                    int age = Integer.parseInt(ageStr);
                    return age>config.getMaxAge() && age<config.getMinAge();
                }
                return true;
            }
        };
        
    }



    class Config {

        private int minAge;

        private int maxAge;

        public int getMinAge() {
            return minAge;
        }

        public void setMinAge(int minAge) {
            this.minAge = minAge;
        }

        public int getMaxAge() {
            return maxAge;
        }

        public void setMaxAge(int maxAge) {
            this.maxAge = maxAge;
        }


    }

}



http://localhost:7000/product-serv/product/1?age=30 不可以访问
http://1ocalhost:7000/product-serv/product/1?age=19 可以访问

4.3过滤器

  • 作用:在请求传递过程中,对请求和响应做一些修改
  • 分类:局部(作用域某一个路由),全局(作用在所有的路由)
  • 生命周期:Pre和Post

在Gateway中,过滤器的生命周期只有两个,Pre和Post

  • Pre:这种过滤器在请求被路由之前调用。我们可利用这种过滤器实现身份验证、在集群中选择请求的微服务,记录调试信息等
  • Post:这种过滤器在路由到微服务以后执行。这种过滤器可用来为响应添加标准的HTTP,Header、收集统计信息和指标、将响应从微服务发送给客户端等。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值