微服务 02

一、网关路由

网关就是网络的关口。数据在网络间传输,从一个网络传输到另一网络时就需要经过网关来做数据的路由和转发以及数据安全的校验。

路由是网关的核心功能之一,决定如何将客户端请求映射到后端服务。

1、快速入门

创建新模块,引入网关依赖,编写启动类,配置路由规则        

依赖:

<?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>hmall</artifactId><groupId>com.heima</groupId><version>1.0.0</version></parent><modelVersion>4.0.0</modelVersion><artifactId>hm-gateway</artifactId><properties><maven.compiler.source>11</maven.compiler.source><maven.compiler.target>11</maven.compiler.target></properties><dependencies><!--common--><dependency><groupId>com.heima</groupId><artifactId>hm-common</artifactId><version>1.0.0</version></dependency><!--网关--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId></dependency><!--nacos discovery--><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency><!--负载均衡--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-loadbalancer</artifactId></dependency></dependencies><build><finalName>${project.artifactId}</finalName><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build>
</project>

 新建yml/yaml文件配置路由

server:port: 8080
spring:application:name: gatewaycloud:nacos:server-addr: 192.168.150.101:8848gateway:routes:- id: item # 路由规则id,自定义,唯一uri: lb://item-service # 路由的目标服务,lb代表负载均衡,会从注册中心拉取服务列表(微服务名,从yaml文件里找的)predicates: # 路由断言,判断当前请求是否符合当前规则,符合则路由到目标服务(请求路径,看controller)- Path=/items/**,/search/** # 这里是以请求路径作为判断规则(有多个路径逗号分割,或者下一行重新写 - Path=/search/**)- id: carturi: lb://cart-servicepredicates:- Path=/carts/**- id: useruri: lb://user-servicepredicates:- Path=/users/**,/addresses/**- id: tradeuri: lb://trade-servicepredicates:- Path=/orders/**- id: payuri: lb://pay-servicepredicates:- Path=/pay-orders/**

路由包含四个属性:

  • id:路由的唯一标示

  • predicates:路由断言,其实就是匹配条件

  • filters:路由过滤器,对请求或响应做特殊处理。

  • uri:路由目标地址,lb://代表负载均衡,从注册中心获取目标微服务的实例列表,并且负载均衡选择一个访问。

Spring中提供了12种基本的RoutePredicateFactory实现:

路由断言

名称

说明

示例

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

权重处理

2、路由过滤

网关中提供了33种路由过滤器,每种过滤器都有独特的作用。 

      routes:- id: item # 路由规则id,自定义,唯一uri: lb://item-service # 路由的目标服务,lb代表负载均衡,会从注册中心拉取服务列表predicates: # 路由断言,判断当前请求是否符合当前规则,符合则路由到目标服务- Path=/items/**,/search/** # 这里是以请求路径作为判断规则(有多个路径逗号分割,或者下一行重新写 - Path=/search/**)filters:- AddResponseHeader=truth, anyone

如果与routes同一级设置 default-filters,就是对所有路由都生效:

      default-filters:- AddResponseHeader=truth, anyone  //所有路由都生效

创建启动类:

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

二、网关登录校验

1、实现思路

单体架构时我们只需要完成一次用户登录、身份校验,就可以在所有业务中获取到用户信息。而微服务拆分后,每个微服务都独立部署,不再共享数据。也就意味着每个微服务都需要做登录校验,这显然不可取。

既然网关是所有微服务的入口,一切请求都需要先经过网关。我们完全可以把登录校验的工作放到网关去做,这样之前说的问题就解决了。

 

 在网关内自定义过滤器,编写登录校验逻辑,并且将过滤器执行顺序定义到NettyRoutingFilter之前,

 2、自定义过滤器

网管过滤器有两种,分别是:

  • GatewayFilter:路由过滤器,作用于任意指定的路由;默认不生效,要配置到路由后生效。
  • GlobalFilter:全局过滤器,作用范围是所有路由;声明后自动生效。

两种过滤器的过滤方法签名完全一样:

/*** 处理请求并将其传递给下一个过滤器* @param exchange 当前请求的上下文,其中包含request、response等各种数据* @param chain 过滤器链,基于它向下传递请求* @return 根据返回值标记当前请求是否被完成或拦截,chain.filter(exchange)就放行了。*/
Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain);

 GlobalFilter定义步骤:

  1. 新建包filters,新建类MyGlobalFilter。
  2. 添加@Component注解。
  3. 实现GlobaFilter接口以及其中的filter方法。
  4. 进行逻辑代码编写
  5. 实现Ordered接口以及其中的方法。(用来定义优先级)
@Component
public class MyGlobalFilter implements GlobalFilter, Ordered {@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {//TODO 模拟登录校验逻辑ServerHttpRequest request = exchange.getRequest();HttpHeaders headers = request.getHeaders();System.out.println("header =" + headers);return chain.filter(exchange);}@Overridepublic int getOrder() {return 0;}
}

3、实现登录校验

需求:在网关中基于过滤器实现登录校验功能

定义步骤与 上面GlobalFilter定义步骤一致,具体代码如下:

@Component
@RequiredArgsConstructor
public class AuthGlobalFilter implements GlobalFilter, Ordered {private final JwtTool jwtTool;private final AuthProperties authProperties;private AntPathMatcher antPathMatcher = new AntPathMatcher();  //是Spring 框架提供的路径匹配工具类。@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {//1、获取requestServerHttpRequest request = exchange.getRequest();//2、判断是否需要做登录拦截if (isExclude(request.getPath().toString())) {//放行return chain.filter(exchange);}//3、获取tokenString token = null;List<String> headers = request.getHeaders().get("authorization");if (headers != null && !headers.isEmpty()) {token = headers.get(0);}Long userId = null;//4、校验并解析tokentry {userId = jwtTool.parseToken(token);} catch (Exception e) {//拦截,设置响应状态码,401// 获取响应对象ServerHttpResponse response = exchange.getResponse();// 设置响应状态码为401(未授权)response.setStatusCode(HttpStatus.UNAUTHORIZED);// 结束响应,不再继续处理请求return response.setComplete();}//5、TODO 传递用户信息System.out.println("userId=" + userId);//6、放行return chain.filter(exchange);}@Overridepublic int getOrder() {return 0;}private boolean isExclude(String path) {// 获取所有需要排除的路径,来自AuthProperties配置类中的excludePaths属性// AuthProperties通过@ConfigurationProperties注解自动绑定配置文件中hm.auth.exclude-paths的值for (String pathPattern : authProperties.getExcludePaths()) {// 使用AntPathMatcher匹配当前路径是否符合排除路径模式// 如果匹配成功,则说明该路径不需要进行身份验证拦截if (antPathMatcher.match(pathPattern, path)) {return true;}}return false;}
}

4、网关传递用户

①在网关的登录校验过滤器中,把获取得到的用户写入请求头。

修改转发到微服务的请求,需要用到ServerWebExchange类提供的API,示例如下:

 修改内容:

     //5、传递用户信息String userInfo = userId.toString();ServerWebExchange swe = exchange.mutate().request(builder -> builder.header("user-info", userInfo)) //要写入的请求头,名字可以自己起,要写入的内容.build();//6、放行return chain.filter(swe);

②在hm-common中编写SpringMVC拦截器,获取登录用户。

public class UserInfoInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {//1、获取用户登录信息String userInfo = request.getHeader("user-info");//2、判断是否获取了用户,如果有,存入ThreadLocalif (StrUtil.isNotBlank(userInfo)) {UserContext.setUser(Long.valueOf(userInfo));}//放行return true;}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {//清理用户UserContext.removeUser();}
}

5、OpenFeign传递用户

OpenFeign中提供了一个拦截器接口,所有由OpenFeign发起的请求都会先调用拦截器处理请求:

public interface RequestInterceptor {/*** Called for every request. * Add data using methods on the supplied {@link RequestTemplate}.*/void apply(RequestTemplate template);
}
    @Beanpublic RequestInterceptor userInfoRequestInterceptor() {return new RequestInterceptor() {@Overridepublic void apply(RequestTemplate template) {Long userId = UserContext.getUser();if(userId != null){template.header("user-info",userId.toString());}}};}

微服务登录解决方案

三、配置管理

微服务配置的问题:

  • 微服务重复配置过多,维护成本高。
  • 业务配置经常变动,每次修改都要重启服务。
  • 网关路由配置写死,如果变更要重启网关。

1、配置共享

①将一些公共的配置进行抽取,放到Nacos->配置列表->新建配置中,

 ${}是可以通过其他配置文件来指明,这些都是不固定的,不能写死,后面的:是添加一个默认值。共享的配置有swagger,log,jdbc

 

②然后将其中的变量值声明出来:

hm:db:database: hm-cart

③拉取共享配置

 基于NacosConfig拉取共享配置代替微服务的本地配置。

SpringCloud在初始化上下文的时候会先读取一个名为bootstrap.yaml(或者bootstrap.properties)的文件,如果我们将nacos地址配置到bootstrap.yaml中,那么在项目引导阶段就可以读取nacos中的配置了。

配置步骤:

        1)引入依赖(帮助完成拉取配置的动作, 读取bootstrap文件,创建bootStrap的上下文)

  <!--nacos配置管理--><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId></dependency><!--读取bootstrap文件--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-bootstrap</artifactId></dependency>

        2)新建bootstrap.yaml(包含服务名字,nacos地址,共享文件的名称)

spring:application:name: cart-serviceprofiles:active: dev  #开发环境(dev)、测试环境(test)、生产环境(prod)cloud:nacos:server-addr: 192.168.100.128:8848config:file-extension: yamlshared-configs:- data-id: shared-jdbc.yaml- data-id: shared-log.yaml- data-id: shared-swagger.yaml

application.yaml变为:

server:port: 8082
feign:okhttp:enabled: true # 开启OKHttp功能hm:db:database: hm-cartswagger:title: "黑马商城购物车服务接口文档"package: com.hmall.cart.controller# keytool -genkeypair -alias hmall -keyalg RSA -keypass hmall123 -keystore hmall.jks -storepass hmall123

2、配置热更新

配置热更新:当修改配置文件中的配置时,微服务无需重启即可使配置生效。

前提条件:

①nacos中要有一个与微服务名有关的配置文件规则:[服务名]-[spring.active.profile].[后缀名]

②微服务中要以特定的方式读取需要热更新的配置属性 新建config包,创建类并定义属性

@Data
@Component
@ConfigurationProperties(prefix = "hm.cart")
public class CartProperties {private Integer maxAmount;
}

在源代码处进行更改:

 private void checkCartsFull(Long userId) {int count = lambdaQuery().eq(Cart::getUserId, userId).count();if (count >= cartProperties.getMaxItems()) {throw new BizIllegalException(StrUtil.format("用户购物车课程不能超过{}", cartProperties.getMaxItems()));}}

3、动态路由

要实现动态路由首先要将路由配置保存到Nacos,当Nacos中的路由配置变更时,推送最新配置到网关,实时更新网关中的路由信息。 

要完成的事情:

①监听Nacos配置变更的消息

②当配置变更时,将最新的路由信息更新到网关路由表

//TODO

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/917044.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/917044.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

04动手学深度学习笔记(上)

04数据操作 import torch(1)张量表示一个数据组成的数组&#xff0c;这个数组可能有多个维度。 xtorch.arange(12) xtensor([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])(2)通过shape来访问张量的形状和张量中元素的总数 x.shapetorch.Size([12])(3)number of elements表…

MCU中的RTC(Real-Time Clock,实时时钟)是什么?

MCU中的RTC(Real-Time Clock,实时时钟)是什么? 在MCU(微控制器单元)中,RTC(Real-Time Clock,实时时钟) 是一个独立计时模块,用于在系统断电或低功耗状态下持续记录时间和日期。以下是关于RTC的详细说明: 1. RTC的核心功能 精准计时:提供年、月、日、时、分、秒、…

Linux 进程调度管理

进程调度器可粗略分为两类&#xff1a;实时调度器(kernel)&#xff0c;系统中重要的进程由实时调度器调度&#xff0c;获得CPU能力强。非实时调度器(user)&#xff0c;系统中大部分进程由非实时调度器调度&#xff0c;获得CPU能力弱。实时调度器实时调度器支持的调度策略&#…

基于 C 语言视角:流程图中分支与循环结构的深度解析

前言&#xff08;约 1500 字&#xff09;在 C 语言程序设计中&#xff0c;控制结构是构建逻辑的核心骨架&#xff0c;而流程图作为可视化工具&#xff0c;是将抽象代码逻辑转化为直观图形的桥梁。对于入门 C 语言的工程师而言&#xff0c;掌握流程图与分支、循环结构的对应关系…

threejs创建自定义多段柱

最近在研究自定义建模&#xff0c;有一个多断柱模型比较有意思&#xff0c;分享下&#xff0c;就是利用几组点串&#xff0c;比如上中下&#xff0c;然后每组点又不一样多&#xff0c;点续还不一样&#xff0c;(比如第一个环的第一个点在左边&#xff0c;第二个环在右边)&#…

Language Models are Few-Shot Learners: 开箱即用的GPT-3(四)

Result续 Winograd-Style Tasks Winograd-Style Tasks 是自然语言处理中的一类经典任务。它源于 Winograd Schema Challenge(WSC),主要涉及确定代词指的是哪个单词,旨在评估模型的常识推理和自然语言理解能力。 这个任务中的具体通常包含高度歧义的代词,但从语义角度看…

BGP高级特性之认证

一、概述BGP使用TCP作为传输协议&#xff0c;只要TCP数据包的源地址、目的地址、源端口、目的端 口和TCP序号是正确的&#xff0c;BGP就会认为这个数据包有效&#xff0c;但数据包的大部分参数对于攻击 者来说是不难获得的。为了保证BGP免受攻击&#xff0c;可以在BGP邻居之间使…

商旅平台怎么选?如何规避商旅流程中的违规风险?

在中大型企业的商旅管理中&#xff0c;一个典型的管理“黑洞”——流程漏洞与超标正持续吞噬企业成本与管理效能&#xff1a;差标混乱、审批脱节让超规订单频频闯关&#xff0c;不仅让企业商旅成本超支&#xff0c;还可能引发税务稽查风险。隐性的合规风险&#xff0c;比如虚假…

Anaconda的常用命令

Anaconda 是一个用于科学计算、数据分析和机器学习的 Python 发行版&#xff0c;包含了大量的预安装包。它配有 conda 命令行工具&#xff0c;方便用户管理包和环境。以下是一些常用的 conda 命令和 Anaconda 的常见操作命令&#xff0c;帮助你高效管理环境和包。1. 环境管理创…

JVM之【Java虚拟机概述】

目录 对JVM的理解 JVM的架构组成 类加载系统 执行引擎 运行时数据区 垃圾收集系统 本地方法库 对JVM的理解 JVM保证了Java程序的执行&#xff0c;同时也是Java语言具有跨平台性的根本原因&#xff1b;Java源代码通过javac等前端编译器生成的字节码计算机并不能识别&…

RabbitMQ+内网穿透远程访问教程:实现异地AMQP通信+Web管理

RabbitMQ是一个开源的消息队列中间件&#xff0c;基于Erlang开发&#xff0c;遵循AMQP&#xff08;Advanced Message Queuing Protocol&#xff0c;高级消息队列协议&#xff09;标准&#xff0c;主要用于实现异步通信、消息解耦和系统间数据传输。它的核心作用是在分布式系统中…

go 语言 timer 与 ticker理论和实例大全

目录 1. 时间之门的钥匙:Timer与Ticker的本质 2. Timer:精准的单次计时 2.1 Timer的基础用法 2.2 停止与重置Timer 2.3 Timer的高级技巧:优雅处理并发 3. Ticker:时间的节拍器 3.1 Ticker的基本用法 3.2 Ticker的高级应用:动态调整周期 4. Timer与Ticker的结合:打…

MySQL 45讲 16-17

全字段排序 explain 中的 using fiesort ,扫描 数据,取出符合判断条件的 数据,到sort buffer中,然后对排序字段采用快速排序进行 排序后直接将 所需字段进行返回 如果 字段长度所占内存大于所分配 的sort buffer ,需要借助 临时文件 进行 数据的存放排序,此时会采用 归并排序,将…

QT项目 -仿QQ音乐的音乐播放器(第四节)

一、RecBox中btUp和btDown按钮clicked处理 选中左右键&#xff08;btUp和btDown按钮&#xff09;然后右击转到槽->click() void RecBox::on_btUp_clicked() {}void RecBox::on_btDown_clicked() {} 二、imageList中图片分组 // recbox.h 中新增 int currentIndex; // 标记…

DeepSeek SEO关键词优化提升流量增长

内容概要DeepSeek SEO关键词优化致力于通过科学的方法&#xff0c;显著提升网站在搜索引擎中的可见度与自然流量。其核心在于深入理解并精准匹配用户的真实搜索意图&#xff0c;而非仅仅堆砌词汇。具体来说&#xff0c;该策略运用深度意图导向策略&#xff0c;确保内容与用户需…

# Ubuntu 系统设置 USB PnP 音频设备为默认设备的完整教程

Ubuntu 系统设置 USB PnP 音频设备为默认设备的完整教程 在使用 Ubuntu 系统时&#xff0c;尤其是在嵌入式设备如 NVIDIA Jetson 系列上&#xff0c;我们经常需要将 USB PnP 音频设备设置为默认设备。本文将详细介绍如何通过命令行配置&#xff0c;使 USB PnP 音频设备在系统重…

Hadoop JMX 配置的完整文档

一、JMX 基础概念与 Hadoop 支持 1、JMX 作用。 Java Management Extensions&#xff08;JMX&#xff09;提供标准 API 监控 JVM 应用运行时状态&#xff08;内存、线程、GC&#xff09;及 Hadoop 组件指标&#xff08;HDFS 容量、RPC 性能、节点状态&#xff09; 2、Hadoop 组…

arm架构系统打包qt程序--麒麟操作系统为例

检查系统架构 uname -a如果显示是aarch644或arm64&#xff0c;说明你使用的是ARM架构&#xff0c;&#xff0c;需要下载ARM版本。 下载对应架构的linuxdeployqt 编写脚本 vim deploy.sh#!/bin/bash APP_NAME"sunny450_silc"# 确保deploy目录存在 mkdir -p deploy# 复…

Kong API Gateway深度解析:插件系统与微服务架构的技术基石

在微服务&#xff08;microservices&#xff09;架构主导的今天&#xff0c;API网关&#xff08;API Gateway&#xff09;作为服务入口的“交通枢纽”&#xff0c;承担着流量调度、安全防护、可观测性&#xff08;observability&#xff09;等核心职责。Kong作为开源API网关领域…

Linux应用开发基础知识——Makefile初级教程(九)

目录 一、Makefile是啥&#xff1f; 1.1、了解几种文件&#xff08;.o 文件和.c文件 &#xff09; 1.2、关于Makefile的写法 1.3、简单使用Makefile基本指令 1.4、引入伪目标 1.5、Makefile的优点 1.6、Makefile的使用 二、Makefile创建和使用变量 2.1、创建变量的目的…