• Spring Cloud:四 【详细】


    目录

    统一网关Gateway

    网关的实现

    搭建网关

    编写配置文件

    路由断言工程

    路由的过滤器

    全局过滤器

    网关过滤器执行顺序

    网关的cors跨域配置

    问题及解决


    统一网关Gateway

    网关的实现

    SpringCloud中存在两种网关

    1. gateway:基于Spring5中提供的WebFlux实现,属于响应式编程,性能更好
    2. zuul:基于Servlet实现,阻塞式编程

    搭建网关

    首先网关也属于微服务的一个模块,也需要注册到Nacos与拉去Nacos的信息,创建gateway模块并引入以下两个依赖。

    1. <dependencies>
    2. <dependency>
    3. <groupId>com.alibaba.cloudgroupId>
    4. <artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
    5. dependency>
    6. <dependency>
    7. <groupId>org.springframework.cloudgroupId>
    8. <artifactId>spring-cloud-starter-gatewayartifactId>
    9. <version>2.2.1.RELEASEversion>
    10. dependency>
    11. dependencies>

    Gateway也是一个服务,需要一个启动类

    1. @SpringBootApplication
    2. public class GatewayApplication {
    3. public static void main(String[] args) {
    4. SpringApplication.run(GatewayApplication.class,args);
    5. }
    6. }

    编写配置文件

    1. server:
    2. port: 10010
    3. spring:
    4. application:
    5. name: gateway
    6. cloud:
    7. nacos:
    8. server-addr: localhost:8848 # nacos的地址
    9. gateway:
    10. routes: # 路由地址
    11. - id: user-server # 路由唯一标识(自定义,只要唯一)
    12. uri: lb://user-server #路由目标地址
    13. predicates: # 路由断言。判断请求是否符合规则
    14. - Path=/user/**
    15. - id: order-service # 路由唯一标识
    16. uri: lb://order-service #路由目标地址
    17. predicates: # 路由断言。判断请求是否符合规则
    18. - Path=/order/**

    启动网关服务,访问网关地址观察结果

    具体流程如下

    路由断言工程

    我们在配置文件中写的断言规则只是字符串,这些字符串会被Predicate Factory读取并处理,转变为路由判断的条件。

    例如Path=从user/**是按照路径匹配,这个规则是由org.springframework.cloud.gateway.handlerpredicate.PathRoutePredicateFactory类来处理的。

    Spring提供了11种基本的Predicate工厂

    名称

    说明

    示例

    After

    是某个时间点后的请求

    -After=2037-01-20T17:42:47.789-07:00[America/Denver]

    Before

    是某个时间点前的请求

    -Before=2031-04-13T15:14:47.433+08:00[Asia/Shanghai]

    Between

    是某两个时间点之前的请求

    -Between=2037-01-20T17:42:47.789-07:00[America/Denver],2037-01-21T17:42:47.789-07:00[America/Denver]

    Cookie

    请求必须包含某些cookie

    - Cookie=chocolate, ch.p

    Header

    请求必须包含某些header

    -Header=X-Request-ld,\d+

    Host

    请求必须是访问某个host (域名)

    -Host=**.somehost.org,**.anotherhost.org

    Method

    请求方式必须是指定方式

    -Method=GET,POST

    Path

    请求路径必须符合指定规则

    -Path=/red/{segment),/blue/**

    Query

    请求参数必须包含指定参数

    -Query=name,Jack或者- Query=name

    RemoteAddr

    请求者的ip必须是指定范围

    -RemoteAddr=192.168.1.1/24

    Weight

    权重处理

    路由的过滤器

    Spring提供了31种不同的路由过滤器工厂,具体可以去看SpringCloud文档,下面案例实现一个最基本的添加请求头过滤器。我们向/order所有请求添加一个gateway=hello world的请求头

    首先添加配置

    1. spring:
    2. cloud:
    3. nacos:
    4. server-addr: localhost:8848 # nacos的地址
    5. gateway:
    6. routes: # 路由地址
    7. - id: order-service # 路由唯一标识
    8. uri: lb://order-service #路由目标地址
    9. predicates: # 路由断言。判断请求是否符合规则
    10. - Path=/order/**
    11. filters:
    12. - AddRequestHeader=gateway,hello world

    在OrderController中添加参数,并打印

    1. @GetMapping("{orderId}")
    2. public Order queryOrderByUserId(@PathVariable("orderId") Long orderId,@RequestHeader(value = "gateway",required = false) String str) {
    3. System.out.println("---------"+str);
    4. // 根据id查询订单并返回
    5. return orderService.queryOrderById(orderId);
    6. }

    访问观察控制台输出。

    成功打印信息。

    刚刚是针对某个路由生效,如果想要每个路由都生效,应该选择默认过滤器配置

    1. spring:
    2. cloud:
    3. nacos:
    4. server-addr: localhost:8848 # nacos的地址
    5. gateway:
    6. routes: # 路由地址
    7. - id: order-service # 路由唯一标识
    8. uri: lb://order-service #路由目标地址
    9. predicates: # 路由断言。判断请求是否符合规则
    10. - Path=/order/**
    11. default-filters:
    12. - AddRequestHeader=gateway,hello world

    全局过滤器

    与Gateway的默认过滤器一样,处理一切进入网关请求和微服务响应。区别在于GatewayFilter通过配置定义,处理逻辑固定,而全局过滤器可以自己实现处理逻辑,实现方式就是实现GlobalFilter接口。下面写一个简单的登录拦截功能

    1. /**
    2. * 登录认证过滤器
    3. */
    4. @Order(-1)
    5. @Component
    6. public class authorizeFilter implements GlobalFilter {
    7. @Override
    8. public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
    9. //第一步获取请求参数
    10. ServerHttpRequest request = exchange.getRequest();
    11. MultiValueMap params = request.getQueryParams();
    12. //获取参数中的authorize参数
    13. String authorize = params.getFirst("authorize");
    14. //判断参数是否等于admin
    15. if (authorize.equals("admin")){
    16. //等于,放行
    17. return chain.filter(exchange);
    18. }
    19. //设置状态码
    20. exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
    21. return exchange.getResponse().setComplete();
    22. }
    23. }

    启动,并不添加验证访问测试

    添加验证参数再次访问

    网关过滤器执行顺序

    请求进入网关会碰到3种过滤器:当前路由过滤器、DefaultFilter、GlobalFilter。

    请求路由后,会将这三种过滤器合并到一个过滤器链(集合)中,排序后依次执行每个过滤器

    首先比较order值,越小越先执行。GlobalFilter的order由我们指定,其他两种过滤器如果没有指定则由Spring指定order值,默认根据声明顺序来从1递增,当order值相同时,会按照defaultFilter>路由过滤器>GlobalFilter的顺序执行。

    网关的cors跨域配置

    跨域:是指域名不同。比如说:

    • 域名不同: www.taobao.com 和 www.taobao.org 与 www.jd.com 和 miaosha.jd.com
    • 域名相同,端口不同: localhost:8080和localhost:8081

    跨域问题:浏览器禁止请求的发起者与服务端发生跨域ajax请求,请求被浏览器拦截的问题。

    解决跨域问题:配置如下信息

    1. spring:
    2. cloud:
    3. gateway:
    4. globalcors:
    5. add-to-simple-url-handler-mapping: true #一定要配置,主要解决options请求被拦截问题
    6. cors-configurations:
    7. '[/**]': #拦截路径
    8. allowedOrigins: #允许哪些网站跨域请求
    9. - "http://localhost:5500"
    10. - "http://www.域名.com"
    11. allowedMethods: #允许的跨域ajax请求方式
    12. - "GET"
    13. - "POST"
    14. - "DELETE"
    15. - "PUT"
    16. - "OPTIONS"
    17. allowedHeaders: "*" #允许在请求中携带的头信息
    18. allowCredentials: true #是否允许携带Cookie
    19. maxAge: 360000 #本次跨域检测的有效期

    编写一个简单的html页面

    1. html>
    2. <html lang="en">
    3. <head>
    4. <meta charset="UTF-8">
    5. <meta http-equiv="X-UA-Compatible" content="IE=edge">
    6. <meta name="viewport" content="width=device-width, initial-scale=1.0">
    7. <title>测试title>
    8. head>
    9. <body>
    10. body>
    11. <script src="https://unpkg.com/axios/dist/axios.min.js">script>
    12. <script>
    13. axios.get("http://localhost:10010/user/1?authorize=admin")
    14. .then(res=> console.log(res.data))
    15. .catch(err=>console.log(err))
    16. script>
    17. html>

    使用VSCode启动该页面

    问题及解决

    如果出现此类错误

    说明该请求没有被放行,可以尝试将配置文件中的localhost修改成127.0.0.1。或者修改C:\Windows\System32\drivers\etc\hosts文件添加如下信息即可

    127.0.0.1 localhost
  • 相关阅读:
    【JVM】Java类的加载机制!
    C++11 之 override
    python网页爬虫xpath应用
    ZPM介绍(3)
    第2章 Elasticsearch入门
    opencv(5): 滤波器
    对 Vue 中虚拟 DOM 的理解及其原理
    解决kafka.errors.NodeNotReadyError: NodeNotReadyError
    MySQL表单的修改与删除
    Chromium Canvas工作流
  • 原文地址:https://blog.csdn.net/zmbwcx/article/details/134095204