11-微服务技术栈(基础):Gateway服务网关

本文涉及的产品
注册配置 MSE Nacos/ZooKeeper,118元/月
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
云原生网关 MSE Higress,422元/月
简介: 微服务中另一重要组件:网关 进行了实战性演练,网关作为分布式架构中的重要中间件,不仅承担着路由分发(重点关注Path规则配置),同时可根据自身负载均衡策略,对多个注册服务实例进行均衡调用。本节我们借助GateWay实现的网关只是技术实现的方案之一,后续大家可能会接触像:Zuul、Kong等,其实现细节或有差异,但整体目标是一致的。

1.为什么需要网关

Gateway网关是我们服务的守门神,所有微服务的统一入口。网关的核心功能特性

  • 请求路由
  • 权限控制
  • 限流

其架构图如下:

权限控制:网关作为微服务入口,需要校验用户是是否有请求资格,如果没有则进行拦截。

路由和负载均衡:一切请求都必须先经过gateway,但网关不处理业务,而是根据某种规则,把请求转发到某个微服务,这个过程叫做路由。当然路由的目标服务有多个时,还需要做负载均衡。

限流:当请求流量过高时,在网关中按照下流的微服务能够接受的速度来放行请求,避免服务压力过大。


什么是API网关,可参考:https://www.yuque.com/xiankanpengyouquandisitiaodongtai/yeq5ax/blo41c

在SpringCloud中网关的实现包括两种:

Zuul是基于Servlet的实现,属于阻塞式编程。而SpringCloudGateway则是基于Spring5中提供的WebFlux,属于响应式编程的实现,具备更好的性能。(响应式变成WebFlux了解请移步至:什么是WebFlux)

2.gateway快速上手

1 创建gateway服务,引入依赖

引入依赖

 org.springframework.cloud

 spring-cloud-starter-gateway

 com.alibaba.cloud

 spring-cloud-starter-alibaba-nacos-discovery

2 编写启动类

package cn.itcast.gateway;


import org.springframework.boot.SpringApplication;

import org.springframework.boot.autoconfigure.SpringBootApplication;


@SpringBootApplication

public class GatewayApplication {


   public static void main(String[] args) {

       SpringApplication.run(GatewayApplication.class, args);

   }

}

3 编写基础配置和路由规则

创建application.yml文件,内容如下(示例配置多个路由规则):

server:

 port: 10010 # 网关端口

spring:

 application:

   name: gateway # 服务名称

 cloud:

   nacos:

     server-addr: localhost:8848 # nacos地址

   gateway:

     routes: # 网关路由配置

       - id: user-service # 路由id,自定义,只要唯一即可

         # uri: http://127.0.0.1:8081 # 路由的目标地址 http就是固定地址

         uri: lb://userservice # 路由的目标地址 lb就是负载均衡,后面跟服务名称

         predicates: # 路由断言,也就是判断请求是否符合路由规则的条件

           - Path=/user/** # 这个是按照路径匹配,只要以/user/开头就符合要求

       - id: order-service # 路由id,自定义,只要唯一即可

         uri: lb://orderservice # 路由的目标地址 lb就是负载均衡,后面跟服务名称

         predicates: # 路由断言,也就是判断请求是否符合路由规则的条件

           - Path=/order/** # 这个是按照路径匹配,只要以/user/开头就符合要求

我们将符合Path 规则的一切请求,都代理到 uri参数指定的地址。本例中,我们将 /user/**开头的请求,代理到lb://userservice,lb是负载均衡,根据服务名拉取服务列表,实现负载均衡。

4 重启测试

重启网关,访问http://localhost:10010/user/1时,符合/user/**规则,请求转发到uri:http://userservice/user/1,效果如下,说明网关路由生效:

5 网关路由流程图

当用户请求过来之后首先请求网关,网关根据自己的路由规则判断决定路由到哪个服务(依赖Nacos注册中心的服务列表信息),同时借助自身负载均衡能力分配到指定服务多个实例中的某一个实例,完成一次请求&响应。


路由配置包括:

  1. 路由id:路由的唯一标示
  2. 路由目标(uri):路由的目标地址,http代表固定地址,lb代表根据服务名负载均衡
  3. 路由断言(predicates):判断路由的规则,
  4. 路由过滤器(filters):对请求或响应做处理

接下来,就重点来学习路由断言和路由过滤器的详细知识。

3.断言工厂

我们在配置文件中写的断言规则只是字符串,这些字符串会被Predicate Factory读取并处理,转变为路由判断的条件,例如Path=/user/**是按照路径匹配,这个规则是由org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory类来处理的,像这样的断言工厂在SpringCloudGateway还有十几个:

名称

说明

示例

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-Id, \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

权重处理

虽然断言规则有很多,但基本使用的都是Path这种路由工程,大家也重点关注此即可。

4.过滤器工厂

GatewayFilter是网关中提供的一种过滤器,可以对进入网关的请求和微服务返回的响应做处理:


1 过滤器种类

Spring提供了31种不同的路由过滤器工厂,具体如下:

名称

说明

AddRequestHeader

给当前请求添加一个请求头

RemoveRequestHeader

移除请求中的一个请求头

AddResponseHeader

给响应结果中添加一个响应头

RemoveResponseHeader

从响应结果中移除有一个响应头

RequestRateLimiter

限制请求的流量

2 请求头过滤器

下面我们以AddRequestHeader 为例来讲解。

需求:给所有进入userservice的请求添加一个请求头:Truth=itcast is freaking awesome!

只需要修改gateway服务的application.yml文件,添加路由过滤即可:

spring:

 cloud:

   gateway:

     routes:

     - id: user-service

       uri: lb://userservice

       predicates:

       - Path=/user/**

       filters: # 过滤器

       - AddRequestHeader=Truth, Itcast is freaking awesome! # 添加请求头

当前过滤器写在userservice路由下,因此仅仅对访问userservice的请求有效。

3 默认过滤器

如果要对所有的路由都生效,则可以将过滤器工厂写到default下。格式如下:

spring:

 cloud:

   gateway:

     routes:

     - id: user-service

       uri: lb://userservice

       predicates:

       - Path=/user/**

     default-filters: # 默认过滤项

     - AddRequestHeader=Truth, Itcast is freaking awesome!

4 总结

过滤器的作用:

① 对路由的请求或响应做加工处理,比如添加请求头

② 配置在路由下的过滤器只对当前路由的请求生效

defaultFilters的作用:

① 对所有路由都生效的过滤器

5.全局过滤器

上一节学习的过滤器,网关提供了31种,但每一种过滤器的作用都是固定的。如果我们希望拦截请求,做自己的业务逻辑则没办法实现。因此需要一种全局过滤器帮我们实现此功能。

1 全局过滤器作用

处理一切进入网关的请求和微服务响应,与GatewayFilter的作用一样。区别在于GatewayFilter通过配置定义,处理逻辑是固定的;而GlobalFilter的逻辑需要自己写代码实现。定义方式是实现GlobalFilter接口。

public interface GlobalFilter {

/**

*  处理当前请求,有必要的话通过{@link GatewayFilterChain}将请求交给下一个过滤器处理

*

* @param exchange 请求上下文,里面可以获取Request、Response等信息

* @param chain 用来把请求委托给下一个过滤器

* @return {@code Mono} 返回标示当前过滤器业务结束

*/

   Mono filter(ServerWebExchange exchange, GatewayFilterChain chain);

}

在filter中编写自定义逻辑,可以实现下列功能:

  • 登录状态判断
  • 权限校验
  • 请求限流等

2 自定义全局过滤器

需求:定义全局过滤器,拦截请求,判断请求的参数是否满足下面条件:

  • 参数中是否有authorization,
  • authorization参数值是否为admin

如果同时满足则放行,否则拦截。其实现只要在gateway中定义一个过滤器:

package cn.itcast.gateway.filters;


import org.springframework.cloud.gateway.filter.GatewayFilterChain;

import org.springframework.cloud.gateway.filter.GlobalFilter;

import org.springframework.core.annotation.Order;

import org.springframework.http.HttpStatus;

import org.springframework.stereotype.Component;

import org.springframework.web.server.ServerWebExchange;

import reactor.core.publisher.Mono;


@Order(-1)

@Component

public class AuthorizeFilter implements GlobalFilter {

   @Override

   public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {

       // 1.获取请求参数

       MultiValueMap params = exchange.getRequest().getQueryParams();

       // 2.获取authorization参数

       String auth = params.getFirst("authorization");

       // 3.校验

       if ("admin".equals(auth)) {

           // 放行

           return chain.filter(exchange);

       }

       // 4.拦截

       // 4.1.禁止访问,设置状态码

       exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN);

       // 4.2.结束处理

       return exchange.getResponse().setComplete();

   }

}

此时我们访问必须追加参数才可以成功:http://localhost:10010/order/101?authorization=admin

3 过滤器执行顺序

请求进入网关会碰到三类过滤器:当前路由的过滤器、DefaultFilter、GlobalFilter

请求路由后,会将当前路由过滤器和DefaultFilter、GlobalFilter,合并到一个过滤器链(集合)中,排序后依次执行每个过滤器:

排序的规则具体如下

  • 每一个过滤器都必须指定一个int类型的order值,order值越小,优先级越高,执行顺序越靠前
  • GlobalFilter通过实现Ordered接口,或者添加@Order注解来指定order值,由我们自己指定
  • 路由过滤器和defaultFilter的order由Spring指定,默认是按照声明顺序从1递增。
  • 当过滤器的order值一样时,会按照 defaultFilter > 路由过滤器 > GlobalFilter的顺序执行。

详细内容,可以查看源码:

org.springframework.cloud.gateway.route.RouteDefinitionRouteLocator#getFilters()方法是先加载defaultFilters,然后再加载某个route的filters,然后合并。

org.springframework.cloud.gateway.handler.FilteringWebHandler#handle()方法会加载全局过滤器,与前面的过滤器合并后根据order排序,组织过滤器链

6.跨域问题

1 什么是跨域

跨域:域名不一致就是跨域,主要包括:

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

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

解决方案:CORS,这个以前应该学习过,这里不再赘述了。不知道的小伙伴可以查看:链接

2 模拟跨域问题

将文件:📎index.html

放入tomcat或者nginx:📎nginx-1.18.0.zip

这样的web服务器中,启动并访问。可以在浏览器控制台看到下面的错误:

从localhost:8090访问localhost:10010,端口不同,显然是跨域的请求。

3 解决跨域问题

在gateway服务的application.yml文件中,添加下面的配置:

spring:

 cloud:

   gateway:

     # 。。。

     globalcors: # 全局的跨域处理

       add-to-simple-url-handler-mapping: true # 解决options请求被拦截问题

       corsConfigurations:

         '[/**]':

           allowedOrigins: # 允许哪些网站的跨域请求

             - "http://localhost:8090"

           allowedMethods: # 允许的跨域ajax的请求方式

             - "GET"

             - "POST"

             - "DELETE"

             - "PUT"

             - "OPTIONS"

           allowedHeaders: "*" # 允许在请求中携带的头信息

           allowCredentials: true # 是否允许携带cookie

           maxAge: 360000 # 这次跨域检测的有效期

7.总结

本节针对微服务中另一重要组件:网关 进行了实战性演练,网关作为分布式架构中的重要中间件,不仅承担着路由分发(重点关注Path规则配置),同时可根据自身负载均衡策略,对多个注册服务实例进行均衡调用。本节我们借助GateWay实现的网关只是技术实现的方案之一,后续大家可能会接触像:Zuul、Kong等,其实现细节或有差异,但整体目标是一致的。

截至目前我们的工程如下:📎cloud-demo.zip

8.推荐阅读资料

相关文章
|
19天前
|
弹性计算 API 持续交付
后端服务架构的微服务化转型
本文旨在探讨后端服务从单体架构向微服务架构转型的过程,分析微服务架构的优势和面临的挑战。文章首先介绍单体架构的局限性,然后详细阐述微服务架构的核心概念及其在现代软件开发中的应用。通过对比两种架构,指出微服务化转型的必要性和实施策略。最后,讨论了微服务架构实施过程中可能遇到的问题及解决方案。
|
5天前
|
NoSQL 前端开发 测试技术
👀探秘微服务:从零开启网关 SSO 服务搭建之旅
单点登录(Single Sign-On,简称SSO)是一种认证机制,它允许用户只需一次登录就可以访问多个应用程序或系统。本文结合网关和SaToken快速搭建可用的Session管理服务。
37 8
|
14天前
|
Cloud Native API 微服务
微服务引擎 MSE 及云原生 API 网关 2024 年 11 月产品动态
微服务引擎 MSE 及云原生 API 网关 2024 年 11 月产品动态。
|
15天前
|
运维 Cloud Native 应用服务中间件
阿里云微服务引擎 MSE 及 云原生 API 网关 2024 年 11 月产品动态
阿里云微服务引擎 MSE 面向业界主流开源微服务项目, 提供注册配置中心和分布式协调(原生支持 Nacos/ZooKeeper/Eureka )、云原生网关(原生支持Higress/Nginx/Envoy,遵循Ingress标准)、微服务治理(原生支持 Spring Cloud/Dubbo/Sentinel,遵循 OpenSergo 服务治理规范)能力。API 网关 (API Gateway),提供 APl 托管服务,覆盖设计、开发、测试、发布、售卖、运维监测、安全管控、下线等 API 生命周期阶段。帮助您快速构建以 API 为核心的系统架构.满足新技术引入、系统集成、业务中台等诸多场景需要
|
24天前
|
弹性计算 持续交付 API
构建高效后端服务:微服务架构的深度解析与实践
在当今快速发展的软件行业中,构建高效、可扩展且易于维护的后端服务是每个技术团队的追求。本文将深入探讨微服务架构的核心概念、设计原则及其在实际项目中的应用,通过具体案例分析,展示如何利用微服务架构解决传统单体应用面临的挑战,提升系统的灵活性和响应速度。我们将从微服务的拆分策略、通信机制、服务发现、配置管理、以及持续集成/持续部署(CI/CD)等方面进行全面剖析,旨在为读者提供一套实用的微服务实施指南。
|
20天前
|
设计模式 负载均衡 监控
探索微服务架构下的API网关设计
在微服务的大潮中,API网关如同一座桥梁,连接着服务的提供者与消费者。本文将深入探讨API网关的核心功能、设计原则及实现策略,旨在为读者揭示如何构建一个高效、可靠的API网关。通过分析API网关在微服务架构中的作用和挑战,我们将了解到,一个优秀的API网关不仅要处理服务路由、负载均衡、认证授权等基础问题,还需考虑如何提升系统的可扩展性、安全性和可维护性。文章最后将提供实用的代码示例,帮助读者更好地理解和应用API网关的设计概念。
48 8
|
21天前
|
弹性计算 Kubernetes API
构建高效后端服务:微服务架构的深度剖析与实践####
本文深入探讨了微服务架构的核心理念、设计原则及实现策略,旨在为开发者提供一套系统化的方法论,助力其构建灵活、可扩展且易于维护的后端服务体系。通过案例分析与实战经验分享,揭示了微服务在提升开发效率、优化资源利用及增强系统稳定性方面的关键作用。文章首先概述了微服务架构的基本概念,随后详细阐述了其在后端开发中的应用优势与面临的挑战,最后结合具体实例,展示了如何从零开始规划并实施一个基于微服务的后端项目。 ####
|
29天前
|
监控 持续交付 数据库
构建高效的后端服务:微服务架构的深度解析
在现代软件开发中,微服务架构已成为提升系统可扩展性、灵活性和维护性的关键。本文深入探讨了微服务架构的核心概念、设计原则和最佳实践,通过案例分析展示了如何在实际项目中有效地实施微服务策略,以及面临的挑战和解决方案。文章旨在为开发者提供一套完整的指导框架,帮助他们构建出更加高效、稳定的后端服务。
|
12天前
|
API
Istio 使用ingress和gateway两种方式公开服务
本文档指导您完成Istio网关的部署与配置。首先安装`istiod`(步骤略过)。接着,创建`ingress.yaml`文件,定义Istio入口网关的服务、部署及权限设置,通过`kubectl apply -f ingress.yaml`命令应用。最后,创建Ingress资源,指定主机名、后端服务及TLS配置,实现对外部请求的路由管理。
18 0
|
18天前
|
JavaScript Java Kotlin
深入 Spring Cloud Gateway 过滤器
Spring Cloud Gateway 是新一代微服务网关框架,支持多种过滤器实现。本文详解了 `GlobalFilter`、`GatewayFilter` 和 `AbstractGatewayFilterFactory` 三种过滤器的实现方式及其应用场景,帮助开发者高效利用这些工具进行网关开发。
104 1