SpringCloud学习--- Zuul详解(附代码包)
Posted 小样5411
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SpringCloud学习--- Zuul详解(附代码包)相关的知识,希望对你有一定的参考价值。
目录
前言
上一篇:Hystrix详解
Zuul(网关)在SpringCloud中非常重要,非常重要,Zuul网关的作用类似nginx的作用,Nginx可以做请求转发,Nginx来管理服务的ip地址,客户端只要访问Nginx的端口即可,具体转发访问哪个服务又Nginx转发,Zuul也有这种功能,并Zuul能认证与授权,如果Zuul认为一个请求有权限,才会进行转发给对应服务。除此之外,如果服务有迭代更改,也只需要改Zuul配置,客户端无需改动,还可限流,优点多多,使用起来却很简单。
优点:
1、请求转发,客户端无需再维护大量服务端口
2、认证和授权操作
3、可做限流与安全
4、项目迭代,导致项目拆分或更改,不用动客户端,只要修改Zuul配置
一、Zuul快速入门
创建一个新module,maven项目,命名为zuul_01
常见几步:导入依赖、配置yml、配置启动类+启动Zuul注解、最后测试
注意:zuul是也是通过在Eureka中注册从而访问其他服务
第一步:导入依赖
<dependencies>
<!--zuul是也是通过在EurekaClient中注册访问其他服务,所以也需要导入Eureka_Client-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
第二步:配置application.yml
# 指定往哪个EurekaServer服务中注册
eureka:
client:
serviceUrl:
defaultZone: http://root:root@localhost:8761/eureka/,http://root:root@localhost:8762/eureka/
# 指定服务名称,为了区分创建的服务
spring:
application:
name: zuul
server:
port: 8001
第三步:启动类,注解开@EnableEurekaClient和@EnableZuulProxy,因为Zuul要在Eureka中注册
@SpringBootApplication
@EnableEurekaClient
@EnableZuulProxy
public class ZuulApplication {
public static void main(String[] args) {
SpringApplication.run(ZuulApplication.class,args);
}
}
启动ZuulApplication,输入localhost:8761看看已经启动的服务,这里你要把我前几篇案例也看了,拿代码运行,都是有关联的
通过Zuul的端口8001,输入服务名+接口就可以访问到对应的服务,过程就是Zuul->Customer->Pay调用
二、Zuul常用配置
2.1 监控界面与忽略服务配置
Zuul监控界面没有Hystrix好看,比较简单,效果如下,配置好的服务可以到Zuul这里看看是否生效,如地址含/customer/**
就会到customer服务找,遇到遇到/eureka/**
就会到eureka服务中找,和nginx相似
那我们怎么配置呢?老生常谈的几步
第一步:导入依赖
新增
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
第二步:配置yml
新增
# zuul的监控界面,开发时配置为*,上线无需配置
management:
endpoints:
web:
exposure:
include: "*"
然后重启,输入http://localhost:8001/actuator/routes
即可
如果想移出某个服务呢?application.yml增加如下配置
重启程序,刷新界面,会发现eureka服务直接移除了,customer服务还在,但是无法访问它
#zuul配置
zuul:
ignored-services: eureka #基于服务名忽略,如要忽略全部服务用*
ignored-patterns: /**/search/** #监控界面还是看得到,但是无法访问,会404
自定义配置方式:如果你想把这个下面路径换个其他名字,可以用自定义配置
#zuul配置
zuul:
ignored-services: eureka #基于服务名忽略,如要忽略全部服务用*
ignored-patterns: /**/pay/** #监控界面还是看得到,但是无法访问,会404
routes:
payClient: /pay/** #服务名:新路径
customer: /user/**
这样就创建了新的可以访问的路径,当然旧的也可以使用,两种等价
不想用旧的,可以忽略,比如我们这里写ignored-services: "*"
试试,重启,刷新,以前的访问方式就忽略了,所以这样就可以按自己所需改访问名字
如下输入http://localhost:8001/user/customer/2
得到下面结果,以前是http://localhost:8001/customer/customer/2
,现在改了下名字而已
我们暂时不用这个忽略,先注释
2.2 灰度发布
什么是灰度发布?
灰度发布就是在版本迭代过程,如app发布了一个新版本,更新的用户用心的接口调用功能,而老用户还是用老接口调用功能,那么采用灰度发布,就能平衡好新老版本,怎么做?两步即可
第一步:Zuul启动类增加@Bean代码块,Zuul是通过版本的方式,新版本Zuul会让对应服务用新版接口,老版本用老的
@Bean
public PatternServiceRouteMapper serviceRouteMapper(){
return new PatternServiceRouteMapper(
"(?<name>^.+)-(?<version>v.+$)",
"${version}/${name}"
);
}
第二步:准备一个服务,弄出两个版本
先做如下操作
将新旧Customer都重启,ZuulApplication也重启,改动的都重启,然后查看Zuul的监控界面,那么新的就会以/v1/customer出现,如果再加customer就会变成/v2/customer,zuul都会自动进行
如果你没有得到v1和v2,只有一个v1,没有v2则证明你的有问题,一般是注册的问题,我就碰到了,最后我思考认为应该让所以服务都注册,然后Eureka中有全部服务,Zuul再注册,它就能获取到所有服务了
启动要按照这个顺序启动就没问题
于是就能根据不同版本进行访问
三、Zuul过滤器
过滤器是Zuul的核心组件,我们先看看它的执行流程,如下图
客户端请求发送到Zuul服务上,首先通过PreFilter过滤器链,这个过滤器可以做限流、权限验证等操作,如果请求无误,则正常放行,请求再次转发给RoutingFilter,RouteFilter会将请求转发到指定服务得到响应结果,再将结果传递回RoutingFilter,RouteFilter再将结果传递给PostFilter过滤器链,最终再将响应信息交给客户端。
提供四种过滤器
3.1 Zuul过滤器快速入门
在zuul模块创建两个自定义过滤器类,继承ZuulFilter,重写四个方法
@Component
public class TestZuulFilter extends ZuulFilter {
@Override
public String filterType() {
return FilterConstants.PRE_TYPE;//设置过滤器类型,前置过滤器
}
@Override
public int filterOrder() {
return FilterConstants.PRE_DECORATION_FILTER_ORDER - 1; //设置过滤器执行顺序,数字越小会先执行,这里比前置小,就会在前置过滤器之前执行
}
@Override
public boolean shouldFilter() {
return true; //是否开启当前过滤器
}
@Override
public Object run() throws ZuulException {
System.out.println("prefix过滤器已经执行");
return null;
}
}
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.exception.ZuulException;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
import org.springframework.stereotype.Component;
@Component
public class TestZuulFilter2 extends ZuulFilter {
@Override
public String filterType() {
return FilterConstants.PRE_TYPE;//设置过滤器类型,前置过滤器
}
@Override
public int filterOrder() {
return FilterConstants.PRE_DECORATION_FILTER_ORDER + 1; //设置过滤器执行顺序,数字越小会先执行,这里比前置小,就会在前置过滤器之前执行
}
@Override
public boolean shouldFilter() {
return true; //是否开启当前过滤器
}
@Override
public Object run() throws ZuulException {
System.out.println("prefix过滤器222已经执行");
return null;
}
}
重启ZuulApplication,然后随机访问一个地址,比如这个http://localhost:8001/v1/customer/version
,控制台就会打印下面结果
FilterConstants.PRE_DECORATION_FILTER_ORDER - 1
的TestZuulFilter先执行,因为越小的数字会先执行,源码中默认为5
3.2 PreFilter实现token校验
创建一个AuthenticFilter,继承ZuulFilter
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.apache.http.HttpStatus;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
import javax.servlet.http.HttpServletRequest;
@Component //一定记得加component交给SPring管理
public class AuthenticFilter extends ZuulFilter {
@Override
public String filterType() {
return FilterConstants.PRE_TYPE;
}
@Override
public int filterOrder() {
return FilterConstants.PRE_DECORATION_FILTER_ORDER - 2;//最前进行校验
}
@Override
public boolean shouldFilter() {
return true;
}
@Override
public Object run() throws ZuulException {
//1、获取request对象
RequestContext currentContext = RequestContext.getCurrentContext();
HttpServletRequest request = currentContext.getRequest();
//2、获取token参数
String token = request.getParameter("token");
//3、对比token
if(token == null || !("123".equals(token))){//假设token查到为123
//4、token校验失败,直接响应数据
currentContext.setSendZuulResponse(false);//不响应
currentContext.setResponseStatusCode(HttpStatus.SC_UNAUTHORIZED);//401
}
return null;
}
}
上面的token实际通过Redis查找、也可以是其他查出token,注意自己定义的Filter要用@Component,交给Spring管理
重启ZuulApplication,浏览器刷新,返回401不可访问HttpStatus.SC_UNAUTHORIZED
就是401状态码,表示未授权,校验失败
token正确则放行
3.3 Zuul的降级
Zuul默认会包括Hystrix依赖,所以不用再导入关于降级的Hystrix依赖,本质是Zuul整合Hystrix实现降级,返回托底数据
创建ZuulFallBack实现降级
import org.springframework.cloud.netflix.zuul.filters.route.FallbackProvider;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.stereotype.Component;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
@Component
public class ZuulFallBack implements FallbackProvider {
@Override
public String getRoute() {
return "*"; //指定全部出现问题的服务都走这个降级方法
}
@Override
public ClientHttpResponse fallbackResponse(String route, Throwable cause) {//route表示服务名
System.out.println("降级的服务:"+route);
cause.printStackTrace();//问题打印
return new ClientHttpResponse() {
@Override
public HttpStatus getStatusCode() throws IOException {
return HttpStatus.INTERNAL_SERVER_ERROR; //INTERNAL_SERVER_ERROR(500, "Internal Server Error"),
}
@Override
public int getRawStatusCode() throws IOException {
return HttpStatus.INTERNAL_SERVER_ERROR.value(); //500状态码
}
@Override
public String getStatusText() throws IOException {
//指定错误信息
return HttpStatus.INTERNAL_SERVER_ERROR.getReasonPhrase();
}
@Override
public void close() {
}
@Override
public InputStream getBody() throws IOException {
String msg = "当前服务:"+ route + ",出现问题";
return new ByteArrayInputStream(msg.getBytes());
}
@Override
public HttpHeaders getHeaders() {
//指定响应头信息
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
return headers;
}
};
}
}
阅读上面代码,有注释
新增睡眠
重启Customer有关服务(两个),再重启ZuulApplication服务,输入地址http://localhost:8001/v2/customer/version?token=123
控制台会打印原因,读超时Read timed out,因为睡眠了
代码:
链接:https://pan.baidu.com/s/1U3ebAqfIS-s_7gqqyuOSGQ
提取码:233x
以上是关于SpringCloud学习--- Zuul详解(附代码包)的主要内容,如果未能解决你的问题,请参考以下文章
SpringCloud学习--- Hystrix详解(附代码包)
SpringCloud学习--- Hystrix详解(附代码包)
SpringCloud学习--- Feign详解(附代码压缩包)