文章目录
一、前言
0. 之前写过两篇Spring Cloud,但是感觉不够具体,所以重新写了一份。
新 Spring Cloud (一) 之 Eureka 服务注册中心
新 SpringCloud (二) 之 Ribbon 负载均衡
新 Spring Cloud (三) 之 Hystrix熔断保护
新 Spring Cloud (四) 之 Fegin远程调用
新 Spring Cloud (五) 之 Zuul 网关
1. 正文
Zuul是Netflix开源的微服务网关,它可以和Eureka、Ribbon、 Hystrix 等组件配合使用。
Zuul的核心是–系列的过滤器,这些过滤器可以完成以下功能。
- 身份认证与安全:识别每个资源的验证要求,并拒绝那些与要求不符的请求。
- 审查与监控:在边缘位置追踪有意义的数据和统计结果,从而带来精确的生产视图。
- 动态路由:动态地将请求路由到不同的后端集群。
- 压力测试:逐渐增加指向集群的流量,以了解性能。
- 负载分配:为每- -种负载类型分配对应容量,并弃用超出限定值的请求。
- 静态响应处理:在边缘位置直接建立部分响应,从而避免其转发到内部集群。
- 多区域弹性:跨越AWS Region进行请求路由,旨在实现ELB ( Elastic Load Balancing )
使用的多样化,以及让系统的边缘更贴近系统的使用者。
Spring Cloud对Zuul进行了整合与增强。目前, Zuul使用的默认HTTP客户端是Apache
HTTP Client,也可以使用RestClient或者okhttp3.0kHttpClient。如果想要使用RestClient,
可以设置ribbon.restclient ,enabled=true ;想要使用okhttp3.0kHttpClient ,可以设置rib-
bon. okhttp . enabled=true。
Zuul网关的架构图:
二、Zuul基本使用
-
创建新模块 EurekaZuul 作为zuul网关。选中引入Zuul依赖和Eureka客户端依赖。Zuul依赖自不必说,引入Eureka客户端的依赖是为了从Eureka注册中心拉取注册已注册的服务。
-
在启动类上加上注解 @EnableZuulProxy 开启zuul网关代理,@EnableDiscoveryClient 注册为Eureka客户端
@SpringBootApplication @EnableZuulProxy // 开启网关代理功能 @EnableDiscoveryClient // 注册人Eureka客户端 public class SpringcloudApplication { public static void main(String[] args) { SpringApplication.run(SpringcloudApplication.class, args); } }
-
yml进行如下配置
spring: application: name: zuul-gateway # 指定服务名 server: port: 9999 #端口号 zuul: routes: eureka-server-provider: /provider/** # /provider/** 路径的请求都映射到的 eureka-server-provider 服务上 eureka-server-consumer: /consumer/** # /provider/** 路径的请求都映射到的 eureka-server-provider 服务上 prefix: /api # 添加路由前缀。用来分辨哪个接口通过了Zuul网关。 eureka: client: service-url: # EurekaServer的地址 defaultZone: http://127.0.0.1:10086/eureka,http://127.0.0.1:10087/eureka
注: Zuul 网关的常用的路由方式有以下三种
1. 使用 path 指定映射路径,serviceId指定服务名zuul: routes: eureka-server-provider: # 路由id,可以随意写 path: /provider/** # 服务将要映射的路径 serviceId: eureka-server-provider # 指定需要路由的服务名
2. 是第一种的简化形式,格式是 ----> 服务名:映射路径
zuul: routes: # 上面简化形式: 服务名:映射路径 eureka-server-provider: /provider/** # /provider/** 路径的请求都映射到的 eureka-server-provider 服务上
3. 不进行配置: 不配置默认将服务名作为映射路径。Zuul默认格式是 ----> 服务名: /服务名/**
-
启动服务,访问服务,如下:
三、Zuul过滤器
1. 简介
Zuul作为网关的其中一个重要功能,就是实现请求的鉴权。而这个动作我们往往是通过Zuul提供的过滤器来实现的。
Zuul提供了一个最顶层的抽象过滤器ZuulFilter。我们通过继承这个抽象类来实现过滤器功能。
public abstract ZuulFilter implements IZuulFilter{
abstract public String filterType();
abstract public int filterOrder();
boolean shouldFilter();// 来自IZuulFilter
Object run() throws ZuulException;// IZuulFilter
}
- shouldFilter:返回一个Boolean值,判断该过滤器是否需要执行。返回true执行,返回false不执行。
- run:过滤器的具体业务逻辑。
- filterType:返回字符串,代表过滤器的类型。包含以下4种:
- pre:请求在被路由之前执行
- route:在路由请求时调用
- post:在route和errror过滤器之后调用
- error:处理请求时发生错误调用
- filterOrder:通过返回的int值来定义过滤器的执行顺序,数字越小优先级越高。
2. 使用场景
- 请求鉴权:一般放在pre类型,如果发现没有访问权限,直接就拦截了
- 异常处理:一般会在error类型和post类型过滤器中结合来处理。
- 服务调用时长统计:pre和post结合使用。
3. 过滤器的生命周期
正常流程:
- 请求到达首先会经过pre类型过滤器,而后到达route类型,进行路由,请求就到达真正的服务提供者,执行请求,返回结果后,会到达post过滤器。而后返回响应。
异常流程:
- 整个过程中,pre或者route过滤器出现异常,都会直接进入error过滤器,在error处理完毕后,会将请求交给POST过滤器,最后返回给用户。
- 如果是error过滤器自己出现异常,最终也会进入POST过滤器,将最终结果返回给请求客户端。
- 如果是POST过滤器出现异常,会跳转到error过滤器,但是与pre和route不同的是,请求不会再到达POST过滤器了。
4. 自定义过滤器实现
创建一个类继承 ZuulFilter 类,并实现其中的方法,最后将其注入到Spring容器中即可。
package com.kingfish.springcloud.filter;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import io.micrometer.core.instrument.util.StringUtils;
import org.apache.http.HttpStatus;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
/**
* @Des: 自定义过滤器
*/
@Component
public class CallFilter extends ZuulFilter {
/**
* 过滤类型
*
* @return
*/
@Override
public String filterType() {
return "pre";
}
/**
* 过滤器顺序,数字越小优先级越高
*
* @return
*/
@Override
public int filterOrder() {
return 10;
}
/**
* 是否执行拦截
*
* @return
*/
@Override
public boolean shouldFilter() {
return true;
}
@Override
public Object run() throws ZuulException {
// 获取zuul提供的上下文对象
RequestContext context = RequestContext.getCurrentContext();
// 从上下文对象中获取请求对象
HttpServletRequest request = context.getRequest();
// 设置编码格式
context.getResponse().setContentType("text/html;charset=UTF-8");
// 获取token信息
String msg = request.getParameter("msg");
// 判断
if (StringUtils.isBlank(msg)) {
// 过滤该请求,不对其进行路由
context.setSendZuulResponse(false);
// 设置响应状态码,401
context.setResponseStatusCode(HttpStatus.SC_UNAUTHORIZED);
// 设置响应信息
context.setResponseBody("{\"status\":\"401\", \"text\":\"来者何人,报上姓名!\"}");
} else if ("张三".equals(msg)) {
// 过滤该请求,不对其进行路由
context.setSendZuulResponse(false);
// 设置响应状态码,401
context.setResponseStatusCode(HttpStatus.SC_FORBIDDEN);
// 设置响应信息
context.setResponseBody("{\"status\":\"403\", \"text\":\"张三不能打车!\"}");
}
// 校验通过,把登陆信息放入上下文信息,继续向后执行
context.set("msg", msg);
return null;
}
}
调用如下:
四、Ribbon负载均衡和Hystrix熔断
Zuul中默认就已经集成了Ribbon负载均衡和Hystix熔断机制。其使用方式和配置和单独使用并无差别。故此不再叙述。
以上:内容部分参考网络
如有侵扰,联系删除。 内容仅用于自我记录学习使用。如有错误,欢迎指正