超详细!利用SpringBoot+SpringCloud做一个问答项目(五)

目录

一、关于Eureka注册中心

1.相关术语

2.Eureka Server集群

3.Eureka Server的自我保护机制

二、Zuul网关

三、处理注册页面

附一:关于$.ajax()函数

附二:关于密码加密


一、关于Eureka注册中心

1.相关术语

  • Eureka Server:Eureka服务器项目,也称之为“注册中心”;
  • Eureka Client:Eureka客户端项目,在分布式集群中,只要是会在Eureka Server中注册的,都是Eureka Client,在整个集群网络中,也可以称之为“节点”;
  • 注册表:每个Eureka Client都会在Eureka Server中进行“注册”,则在Eureka Server中就会存在所有Eureka Client的汇总信息,这个汇总信息就是注册表;
  • 抓取(fetch):每个Eureka Client会定期从Eureka Server抓取注册表,使得Eureka Client自身是保存了注册表的,即使后续Eureka Server因为故障从集群中下线了,各Eureka Client还可以根据本地保存的注册表实现相互访问;
  • 心跳周期:每个Eureka Client在每间隔一段时间就会向Eureka Server发送一段数据,表示“我还处于正常运行状态”,这个间隔时间就是“心跳周期”,默认是 30秒,在每次发送心跳时,还会再次从Eureka Server抓取注册表,如果注册表发生了变化,则Eureka Client本地缓存的注册表会进行增量更新;
  • 续订租约:Eureka Client每个心跳周期向Eureka Server发送数据的形为就称之为“续订租约”;
  • 服务剔除:如果Eureka Server在若干个心跳周期之后都没有接收到某一个Eureka Client的“续订”数据,就会将其从注册表中移除。

2.Eureka Server集群

如果整个分布式集群中只有1个Eureka Server,万一这个Eureka Server宕机,其实,其它各Eureka Client也可以通过此前本地缓存的注册表实现相互访问,但是,如果此时新上线了一些服务,或者原有的某些服务变得不可用,各Eureka Client是无法知晓的。

为了提高Eureka Server的可用性,可以搭建Eureka Server集群,也就是使用多个Eureka Server,这样的话,即使其中某些Eureka Server宕机了,只要至少还存在1个Eureka Server是可用的,就不会出问题!

关于Eureka Server集群,其核心思想在于:每个Eureka Server也把自己当成Eureka Client,自己都去别的Eureka Server注册,也从别的Eureka Server抓取注册表,最终,每个Eureka Server都可以通过增量更新得到完整的注册表,而各Eureka Client会尝试在各个Eureka Server中注册。

假设使用3个Eureka Server,它们的服务器主机的IP地址和端口号分别是192.168.0.1:8761192.168.0.2:8762192.168.0.3:8763

在第1台Eureka Server中配置:

# 端口号
server.port=8761
# 主机名
eureka.instance.hostname=eureka1
# 自身去别的Eureka Server注册时的注册地址,多个地址使用逗号分隔
eureka.client.service-url.defaultZone=http://192.168.0.2:8762/eureka, http://192.168.0.3:8763/eureka
# 自身需要抓取注册表(去别的Eureka Server抓取注册表),可以省略
eureka.client.fetch-registry=true
# 自身需要注册(去别的Eureka Server注册),可以省略
eureka.client.register-with-eureka=true

同理,在第2台Eureka Server中配置:

server.port=8762
eureka.instance.hostname=eureka2
eureka.client.service-url.defaultZone=http://192.168.0.1:8761/eureka, http://192.168.0.3:8763/eureka

在第3台Eureka Server中配置:

server.port=8763
eureka.instance.hostname=eureka3
eureka.client.service-url.defaultZone=http://192.168.0.1:8761/eureka, http://192.168.0.2:8762/eureka

最终,在各Eureka Client中配置:

eureka.client.service-url.defaultZone=http://192.168.0.1:8761/eureka, http://192.168.0.2:8762/eureka, http://192.168.0.3:8763/eureka

3.Eureka Server的自我保护机制

Eureka Server在运行期间会统计“丢失心跳比例”,任何连续3次续订失败(连续3个心跳周期都没有收到同一个Eureka Client的续订)的Eureka Client都会被认为存在不干净的终止,如果15分钟之内超过85%的Eureka Client都没有正常的心跳,可以视为出现大规模的网络瘫痪,或者只是Eureka Server出了问题,则Eureka Server就会开启自我保护机制,其表现就是在Eureka状态页面提示警告信息:

以上警告信息如下:

EMERGENCY! EUREKA MAY BE INCORRECTLY CLAIMING INSTANCES ARE UP WHEN THEY'RE NOT. RENEWALS ARE LESSER THAN THRESHOLD AND HENCE THE INSTANCES ARE NOT BEING EXPIRED JUST TO BE SAFE.

大意如下:

注意!Eureka可能错误的将一些已经下线的实例声明为在线,为了保险起见,由于续订租约尚且低于阈值,因此这些实例不会被声明为过期!

首先,这个自我机制是可以取消的:

# 关闭自我保护机制
eureka.server.enable-self-preservation=false
  • 一旦开启自我保护机制,会有如下表现:
  • Eureka Server不再将没有接收到正常心跳的Eureka Client从注册表中移除;
  • Eureka Server依然可以接收新上线的Eureka Client的续订租约的请求,但是,并不会将新的注册表发给各Eureka Client;
  • 当视为网络稳定后,将恢复正常运行状态,自我保护机制会自动关闭。

二、Zuul网关

Zuul的作用是“网关路由”,当使用了Zuul以后,在项目中,需要访问某个服务时,都不再直接访问该服务,而是访问网关,由网关将访问的请求转发到处理请求的服务器。所以,网关路由提供了整个项目的统一入口!

在分布式集群中,网关路由是一个专门的服务器,需要有专门的应用程序运行在这台服务器上!所以,在straw中创建新的子模块项目straw-gateway

当项目创建出来后,先在pom.xml中调整父级项目,及依赖(需要使用zuuleureka-client依赖):

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>cn.tedu</groupId>
        <artifactId>straw</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
    <groupId>cn.tedu</groupId>
    <artifactId>straw-gateway</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>straw-gateway</name>

    <dependencies>
        <!-- 网关路由 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
        </dependency>
        <!-- Eureka Client -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
    </dependencies>

</project>

由于Zuul也是Spring Cloud家族的,在straw父项目中已经管理了整个Spring Cloud家族的依赖,所以,在straw-gateway项目中不需要指定使用的Zuul的版本,是直接应用父项目中管理的Spring Cloud家族的版本!

当前网关项目必须是一个Eureka Client,否则,就不会从Eureka Server抓取注册表,就更不可能知道分布式集群中有哪些服务!

然后,在application.properties中添加配置:

# 服务器端口号
# HTTP协议的默认端口是80,在访问时,不需要在URL中显式的指定端口号
# 如果使用的是Linux / MacOS系统,可能因为系统设置的问题,不能直接使用80端口
server.port=80

# 转发规则
zuul.routes.api-user.service-id=api-user
zuul.routes.api-user.path=/api/**

然后,在配置类(启动类就是一个配置类)的声明之前添加@EnableZuulProxy注解:

然后,依次启动straw-eureka-server > straw-api-user > straw-gateway这3个项目,原本可以通过以下URL测试注册:

http://localhost:8080/v1/users/reg

现在可以改为通过以下URL测试注册:

http://localhost/api/v1/users/reg

关于当前straw-gateway项目的配置中:

# 转发规则
zuul.routes.api-user.service-id=api-user
zuul.routes.api-user.path=/api/**

使用zuul.routes作为前缀的属性是用于配置转发规则的,接下来的api-user是自定义的名称,只需要保证在同一系列的配置中使用相同的名称即可,也就是说,以上配置也可以改为:

# 转发规则
zuul.routes.a.service-id=api-user
zuul.routes.a.path=/api/**

由于网关需要将若干种不同的请求转发到不同的应用服务器,所以,在一个项目中可能需要配置若干套转换规则,则推荐使用“应用程序名称”作为这里的名称!

以上配置的path表示将什么样的请求进行转发,当配置为以上值时,则表示:当接收到的请求是以/api/作为前缀的任何请求(因为使用了2个星号作为通配符,则表示任何请求)都将执行转发!

而以上配置的service-id就表示转发到哪里去,或者“使用哪个应用服务器处理该请求”,所以,service-id的值必须是另一个应用服务器配置的spring.application.name属性的值!

在处理转发时,可以认为:把URL中的/api/去掉,剩下的部分就是原来的straw-api-user项目中设计的请求路径。

注意:当实现了路由转发后,其实,通过原本的http://localhost:8080/v1/users/reg和新的http://localhost/api/v1/users/reg都可以实现完全相同的访问!这是开发阶段的运行效果,在实际部署时,只有straw-gateway项目所在的服务器是可以对外连接网络的,而straw-api-user项目的服务器只是与straw-gateway项目的服务器在同一个局域网中,对外是不可见的!


三、处理注册页面

页面相关文件可以从我的github:https://github.com/jiangyangsong去下载

将下载得到的压缩包解压到任何位置,得到:

将以上所有文件全部复制到straw-gateway项目的resources/static文件夹中(如果static文件夹不存在,则自行创建):

完成后,点击Build菜单中的Rebuild,避免某些文件没有被建立索引而导致不识别的问题。

重新启动项目后,可以通过 http://localhost/register.html 打开注册页面:

先在项目的resources/static/js文件夹下创建register.js文件:

然后,在register.html中引用该文件:

则该页面所需要使用的JavaScript程序代码都可以写在register.js文件了。

当使用Vue管理页面内容时,需要先确定页面的哪个区域是需要被Vue进行管理的,然后,在这个区域的最外层的标签上添加id,用于对应Vue对象!当前“注册”页面比较简单,找一个能够包裹整个表单的标签即可,例如:

然后,还需要处理“提交表单”的事件,在Vue中,可以使用v-on:事件名称="响应函数"来绑定事件,例如:

然后,在register.js中,需要创建Vue对象,并声明以上绑定的函数

然后,重启straw-gateway项目,刷新注册页面,填写符合基本格式的数据后,点击注册按钮,就可以弹出以上警告:

接下来,可以准备完成“注册”功能,由于页面中并不要求输入“用户名”,所以需要先调整服务器端的功能,不检查用户名,包括:在RegisterStudentDTO类的username属性之前不添加检查的注解:

然后,在UserServiceImpl处理注册时,去掉此前编写的“检查用户名”相关的代码:

为了便于获取表单中的数据,先为表单标签<form>配置id

然后,回到register.js中,关于register函数:

完成后,再次重新启动项目,刷新页面,即可通过页面实现注册!


附一:关于$.ajax()函数

在jQuery中的$.ajax()函数的作用是:发出异步请求,接收响应的结果。

关于$.ajax()函数,常用的属性有:

url:将请求提交到服务器端的哪个路径,取值可以是相对路径,也可以是绝对路径;

data:需要提交的请求参数,参数的格式可以是:

  • 'username=root&password=1234&phone=13800138001'
  • {
        username: 'root',
        password: '1234',
        phone: '13800138001'
    }
  • $('#form-id').serialize(); // 要求表单中的控件(例如输入框)的名称与服务器端要求的名称相同
  • new FormData($('#form-id')[0]); // 仅当处理文件上传时必须使用这种方式

type:请求类型,常用取值有GETPOST,其中,GET是默认值,可以不写;

dataType:服务器端响应的结果的类型,常用取值有jsontextxml等,具体取值需要根据服务器端响应时的响应头(Response Headers)中的Content-Type来决定,当然,$.ajax()函数会自行判断,所以,该属性可以不配置;

success:服务器端成功响应时(响应的HTTP状态码是2xx,例如200)的回调函数,取值为函数,其中,函数的参数就是服务器端响应的数据;

error:服务器端错误响应时(响应的HTTP状态码不是2xx,例如302、404、405、500、504等)的回调函数。


附二:关于密码加密

在处理用户注册时,应该将用户提交的原始密码(密码原文)进行加密处理,最终将加密后得到的数据(密文)存储到数据库中!不要将原始密码直接存储到数据库中,否则,如果出现数据库泄密,就会导致用户数据隐私甚至财产的安全问题!

需要注意的是:不可以使用加密算法来处理需要保存的密码!因为所有的加密算法都是可以逆向运算 的,只要能得到算法类型、加密参数,就可以根据密文逆向运算得到原文!由于数据库泄密的原因大概 率是内部员工的行为,所以,算法类型、加密参数也可能会泄密,则使用加密算法运算得到的密码就没 有意义了。

适合用于处理需要保存的密码的算法是消息摘要算法,这种算法是不可逆向运算的,即使将密文、算法类型、加密参数等都作为已知条件,也不可能通过逆向运算得到原文!

消息摘要算法也称之为数字摘要算法,或简称为摘要算法,其最初的设计目的是为了验证“消息/数据”在 传输之后的可靠性

例如X计算机将一篇文章发到了Y计算机,Y计算机怎么确定收到的文章就是X计算机当初发出的文章呢? 毕竟在网络传输过程中,可能因为网络设备的原因丢失一部分数据,甚至可能因为被黑客入侵而改写了 数据!

为了解决这个问题,在X计算机发送文章的同时,还使用消息摘要算法对文章进行运算,得到“摘要”数据 (相对文章而言,摘要数据的长度非常简短),并且摘要数据也发送到了Y计算机,所以,Y计算机是收 到了文章和摘要数据的,并且,Y计算机也会使用相同的消息摘要算法对文章进行运算,得到另一个摘 要数据,与X计算机发过来摘要数据进行对比,如果2个摘要数据完全相同,则视为“收到的文章就是X计 算机发出的文章”,否则,将视为“收到的文章是不可靠的”。

在实际应用中,消息摘要最典型的用途有:

  • 验证下载的文件是否正确,例如Eclipse的官网中,在每个版本的Eclipse的下载页面,都显示了该 版本软件通过SHA-512算法(消息摘要算法中的一种)运算得到的结果,当用户下载了Eclipse以 后,也可以使用SHA-512对下载到的文件进行运算,对比Eclipse官网的摘要结果,以判断下载得 到的文件是否正确:
  • 在使用网盘时,如果上传Eclipse的安装包,虽然该安装包可能有几百兆,但是可以瞬间完成上传,但是,如果上传一张自拍照片,虽然只有几兆,但是上传花的时间可能更多!是因为网盘在上传之前,会将上传的文件进行摘要运算,如果在网盘服务器有同样的摘要结果,则表示网盘服务器上已经有相同的文件,则不会执行上传,而是把网盘服务器上的文章链接给客户端使用即可,而自拍照都是私密数据,不存在重复的,所以,上传前的检查结果将会是“网盘服务器上没有这个文件”,就必须实际的执行文件上传!

关于消息摘要算法,无论是具体的哪一种,都具备以下特征(使用固定的一种消息摘要算法进行运算):

  • 某种消息摘要算法的运算结果的长度是固定的,例如,无论原文有多长, MD5 的运算结果一定是 32位长度的十六进制数,而 SHA-512 的运算结果一定是128位长度的十六进制数; 
  • 原文相同时,反复运算,得到的摘要结果:相同/不同?
  • 原文不同时,反复运算,得到的摘要结果:相同/不同?

Spring框架自带 MD5 算法的API,调用 DigestUtils 工具类的API即可实现:

@Test
void md5Hex() {
String rawPassword = "123456";
String encodePassword = DigestUtils.md5DigestAsHex(rawPassword.getBytes());
System.err.println("encodePassword=" + encodePassword);
// 123456 -> e10adc3949ba59abbe56e057f20f883e
}

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值