SpringCloud(三) Zuul
Zuul
有了eureka 、 feign 和 hystrix 后,基本上就搭建了简易版的分布式项目,但仍存在一些问题,比如:
1、如果我们的微服务中有很多个独立服务都要对外提供服务,那么我们要如何去管理这些接口?特别是当项目非常庞大的情况下要如何管理?
2、在微服务中,一个独立的系统被拆分成了很多个独立的服务,为了确保安全,权限管理也是一个不可回避的问题,如果在每一个服务上都添加上相同的权限验证代码来确保系统不被非法访问,那么工作量也就太大了,而且维护也非常不方便。
所以出现了网关,它就像一个安检站一样,所有外部的请求都需要经过它的调度与过滤,然后 API 网关来实现请求路由、负载均衡、权限验证等功能。
使用 Zuul 构建 API 网关
创建spring boot工程并添加依赖:
<!--添加 spring cloud 的 zuul 的起步依赖--> <dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
<!--添加 spring cloud 的 eureka 的客户端依赖--> <dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
在入口类上添加@EnableZuulProxy 注解,开启 Zuul 的 API 网关服务功能:
@SpringBootApplication
@EnableEurekaClient
@EnableZuulProxy
public class SpringcloudZuulApplication { public static void main(String[] args) {
SpringApplication.run(SpringcloudZuulApplication.class, args);
} }
在application.yml中添加路由规则
# 配置路由规则
zuul:
routes:
hello:
path: /api-zuul/**
serviceId: springcloud-consumer
说明:以上配置的路由规则就是匹配所有符合/api-zuul/**的请求,只要路径中带有/api-zuul/都将被转发到 springcloud-consumer 服务上。比如:localhost:8766/api-zuul/web/hello转发到 http://localhost:8764/web/hello
构建成功
使用 Zuul 进行请求过滤
定义一个过滤器类并继承自 ZuulFilter,并将该 Filter 作为一个 Bean:
@Component
public class AuthFilter extends ZuulFilter {
@Override
public String filterType() {
return "pre";
} @Override
public int filterOrder() {
return 0;
} @Override
public boolean shouldFilter() {
return true;
} @Override
public Object run() throws ZuulException {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
String token = request.getParameter("token");
if (token == null) {
ctx.setSendZuulResponse(false);
ctx.setResponseStatusCode(401); ctx.addZuulResponseHeader("content-type","text/html;charset=utf-8");
ctx.setResponseBody("非法访问");
}
return null;
}
}
- filterType 方法的返回值为过滤器的类型,决定了过滤器在哪个生命周期执行,pre 表示在路由之前执行过滤器,其他值还有 post、error、route 和 static,当然也可以自定义。
- filterOrder 方法表示过滤器的执行顺序,当过滤器很多时,我们可以通过该方法的返回值来指定过滤器的执行顺序。
- shouldFilter 方法用来判断过滤器是否执行,true 表示执行,false 表示不执行。
- run 方法则表示过滤的具体逻辑,如果请求地址中携带了 token 参数的话,则认为是合法请求,否则为非法请求,如果是非法请求的话,首先设置ctx.setSendZuulResponse(false),表示不对该请求进行路由,然后设置响应码和响应值。这个 run 方法的返回值目前暂时没有任何意义,可以返回任意值。
不携带token,localhost:8766/api-zuul/web/hello
Zuul 的路由规则
在前面的例子中,
zuul:
routes:
hello:
path: /api-zuul/**
serviceId: springcloud-consumer
当访问地址符合 /api-zuul/ 规则的时候,会被自动定位到springcloud-consumer 服务上,有点麻烦,还可以简化为:
zuul:
routes:
springcloud-consumer: /api-zuul/**
zuul.routes 后面跟着的是服务名,服务名后面跟着的是路径规则,这种配置方式更简单。
默认情况下,Eureka 上所有注册的服务都会被 Zuul 创建映射关系来进行路由。
#默认的规则
zuul.routes.springcloud-consumer.path=/springcloud-consumer/**
zuul.routes.springcloud-consumer.serviceId=springcloud-consumer
但如果希望 springcloud-service-provider 作为服务提供者只对服务消费者提供服务,不对外提供服务:
zuul.ignored-services=springcloud-service-provider
还可以进一步细化,比如不想给/hello 接口路由:
zuul.ignored-patterns=/**/hello/**
也可以统一的为路由规则增加前缀:
zuul.prefix=/myapi
路由规则通配符:
一般情况下 API 网关只是作为各个微服务的统一入口,但是有时候我们可能也需要在 API 网关服务上做一些特殊的业务逻辑处理,那么我们可以让请求到达 API 网关后,再转发给自己本身,由 API 网关自己来处理,那么我们可以进行如下的操作:
@RestController
public class GateWayController {
@RequestMapping("/api/local")
public String hello() {
return "exec the api gateway.";
}
}
在 application.yml 中:
zuul:
routes:
gateway:
path: /gateway/**
url: forward:/api/local
Zuul 的异常处理
首先看一下Zuul 请求的生命周期:
- 正常情况下所有的请求都是按照 pre、route、post 的顺序来执行,然后由 post 返回 response
- 在 pre 阶段,如果有自定义的过滤器则执行自定义的过滤器
- pre、routing、post 的任意一个阶段如果抛异常了,则执行 error 过滤器
有两种方式统一处理异常:
禁用 zuul 默认的异常处理 SendErrorFilter 过滤器,然后自定义我们自己的 Errorfilter 过滤器
zuul:
routes:
springcloud-consumer: /api-zuul/**
SendErrorFilter:
error:
disable: true
@Component
public class ErrorFilter extends ZuulFilter {
private static final Logger logger =
LoggerFactory.getLogger(ErrorFilter.class);
@Override
public String filterType() {
return "error";
}
@Override
public int filterOrder() {
return 1;
}
@Override
public boolean shouldFilter() {
return true;
}
@Override
public Object run() throws ZuulException {
try {
RequestContext context = RequestContext.getCurrentContext();
ZuulException exception = (ZuulException)context.getThrowable();
logger.error("进入系统异常拦截", exception);
HttpServletResponse response = context.getResponse();
response.setContentType("application/json; charset=utf8");
response.setStatus(exception.nStatusCode);
PrintWriter writer = null;
try {
writer = response.getWriter();
writer.print("{code:"+ exception.nStatusCode +",message:\""+
exception.getMessage() +"\"}");
} catch (IOException e) {
e.printStackTrace();
} finally {
if(writer!=null){
writer.close();
}
}
} catch (Exception e) {
ReflectionUtils.rethrowRuntimeException(e);
}
return null;
}
}
在 AuthFiler 里的run()方法添加异常
int i = 10 / 0
自定义全局 error 错误页面
开启 zuul 默认的异常处理 SendErrorFilter 过滤器,并注释掉 ErrorFilter 类
@RestController
public class ErrorHandlerController implements ErrorController {
/**
* 出异常后进入该方法,交由下面的方法处理
*/
@Override
public String getErrorPath() {
return "/error";
}
@RequestMapping("/error")
public Object error(){
RequestContext ctx = RequestContext.getCurrentContext();
ZuulException exception = (ZuulException)ctx.getThrowable();
return exception.nStatusCode + "--" + exception.getMessage();
}
}
SpringCloud(三) Zuul的更多相关文章
- springcloud学习之路: (三) springcloud集成Zuul网关
网关就是做一下过滤或拦截操作 让我们的服务更加安全 用户访问我们服务的时候就要先通过网关 然后再由网关转发到我们的微服务 1. 新建一个网关服务Module 2. 依然选择springboot工程 3 ...
- Oauth2.0 整合springCloud的Zuul 解决关键BUG 报错信息:Principal must not be null
不清楚Oauth2.0 的 可以查看我前几篇博文 2018.4.8 补充 我出现这个原因:是我在资源服务器使用了 如下图所示 Principal Oauth2.0 提供的获取用户信息的方法 使其找到相 ...
- SpringCloud之Zuul:服务网关
Zuul在Web项目中的使用见上文<SpringBoot中使用Zuul>,下面例子为Zuul在Spring Cloud的使用. 开发工具:IntelliJ IDEA 2019.2.3 一. ...
- Spring-Cloud之Zuul路由网关-6
一.为什么需要Zuul? Zuul 作为微服务系统的网关组件,用于构建边界服务( Edge Service ),致力于动态路由.过滤.监控.弹性伸缩和安全.Zuul 作为路由网关组件,在微服务架构中有 ...
- SpringCloud之Zuul网关原理及其配置
Zuul是spring cloud中的微服务网关.网关: 是一个网络整体系统中的前置门户入口.请求首先通过网关,进行路径的路由,定位到具体的服务节点上. Zuul是一个微服务网关,首先是一个微服务.也 ...
- 非常全面的讲解SpringCloud中Zuul网关原理及其配置,看它就够了!
Zuul是spring cloud中的微服务网关.网关:是一个网络整体系统中的前置门户入口.请求首先通过网关,进行路径的路由,定位到具体的服务节点上. Zuul是一个微服务网关,首先是一个微服务.也是 ...
- SpringCloud网关ZUUL集成consul
最近一直在搞基于springcloud的微服务开发,为了不限定微服务开发语言,服务发现决定采用consul不多说上代码 pom文件 <project xmlns="http://mav ...
- SpringCloud系列——Zuul 动态路由
前言 Zuul 是在Spring Cloud Netflix平台上提供动态路由,监控,弹性,安全等边缘服务的框架,是Netflix基于jvm的路由器和服务器端负载均衡器,相当于是设备和 Netflix ...
- springcloud的Zuul配置重试和fallback
可以参考如下blog: SpringCloud学习03之api服务网关zuul反向代理及重试配置 springCloud学习04之api服务网关zuul回退fallback 注意:重试的开启需要处理幂 ...
随机推荐
- MySQL插入大量数据探讨
笔者想进行数据库查询优化探索,但是前提是需要一个很大的表,因此得先导入大量数据至一张表中. 准备工作 准备一张表,id为主键且自增: 方案一 首先我想到的方案就是通过for循环插入 xml文件: &l ...
- for no other reason than because
在狄更斯的<A Child History of England>中有段话: After some disputing among the priests, who said that a ...
- day28 进程(Process)
day28 进程(Process) 1.进程的概念 进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础. # 进程是系统进行 ...
- flink---实时项目--day02-----1. 解析参数工具类 2. Flink工具类封装 3. 日志采集架构图 4. 测流输出 5. 将kafka中数据写入HDFS 6 KafkaProducer的使用 7 练习
1. 解析参数工具类(ParameterTool) 该类提供了从不同数据源读取和解析程序参数的简单实用方法,其解析args时,只能支持单只参数. 用来解析main方法传入参数的工具类 public c ...
- 浏览器相关,关于强缓存、协商缓存、CDN缓存。
强缓存和协商缓存 在介绍缓存的时候,我们习惯将缓存分为强缓存和协商缓存两种.两者的主要区别是使用本地缓存的时候,是否需要向服务器验证本地缓存是否依旧有效. 顾名思义,协商缓存,就是需要和服务器进行协商 ...
- 修改 Gradle 插件(Plugins)的下载地址(repositories)
Gradle 也可以用下面的方式声明使用的插件: 1234 // build.gradleplugins { id 'com.example.plugin', version '1.0'} 其实是从 ...
- 数组实现堆栈——Java实现
1 package struct; 2 3 4 //接口 5 interface IArrayStack{ 6 //栈的容量 7 int length(); 8 //栈中元素个数(栈大小) 9 int ...
- centos 7 重新获取IP地址
1.安装软件包 dhclient # yum install dhclient 2.释放现有IP # dhclient -r 3.重新获取 # dhclient 4.查看获取到到IP # ip a
- 机器学习算法中的评价指标(准确率、召回率、F值、ROC、AUC等)
参考链接:https://www.cnblogs.com/Zhi-Z/p/8728168.html 具体更详细的可以查阅周志华的西瓜书第二章,写的非常详细~ 一.机器学习性能评估指标 1.准确率(Ac ...
- python初探——pandas使用
一.简介 pandas 是基于NumPy 的一种工具,该工具是为了解决数据分析任务而创建的.Pandas 纳入了大量库和一些标准的数据模型,提供了高效地操作大型数据集所需的工具.pandas提供了大量 ...