开篇点题
在微服务架构中,需要几个基础的服务治理组件,包括服务注册与发现、服务消费、负载均衡、断路器、智能路由、配置管理等,由这几个基础组件相互协作,共同组建了一个简单的微服务系统。
本章将讲解zuul(路由)这个组件,希望大家可以有个简单的入门。
Zuul简介
Zuul的主要功能是路由转发和过滤器。路由功能是微服务的一部分,比如/api/user转发到到user服务,/api/shop转发到到shop服务。zuul默认和Ribbon结合实现了负载均衡的功能。
zuul有以下功能:
Authentication
Insights
Stress Testing
Canary Testing
Dynamic Routing
Service Migration
Load Shedding
Security
Static Response handling
Active/Active traffic management
本章要点
1.学会配置zuul和eureka集成
2.zuul常用配置介绍
3.zuul调用方式介绍
...评论区内所有解答(有问必有答)
好了我们先开始个简单的入门
(今天2019.1.6 晚上10:40简单记录下)
Demo开始
本章节所有代码以springcloud-02-getway-zuul模块进行讲解(文末共享代码)
模块构建:
构建两个生产者、注册中心、路由
spring-cloud-producter1-002(生产者1)
spring-cloud-producter2-002(生产者2)
spring-cloud-eureka-002(注册中心)
spring-cloud-zuul-002(智能路由,本章讲解内容)
操作流程启动 注册中心(自然第一个先启动)、之后再启动两个生产者
验证是否启动成功,怎么验证?好了,别闹,访问注册中心不就可以了吗
通过下图我们可以看到生产者已经注册进来了,可以看到相应的启动端口
至于生产者和注册中心的代码在前面已讲解,本篇不再重复。
路由zuul构建
pom引入
<dependency> <groupId>org.springframework.retry</groupId> <artifactId>spring-retry</artifactId> </dependency> <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>
启动类 加注解@EnableZuulProxy
@Bean注入了token认证的一个bean(演示其他功能使用)
@SpringBootApplication @EnableZuulProxy public class SpringCloudZuul002Application { public static void main(String[] args) { SpringApplication.run(SpringCloudZuul002Application.class, args); System.out.println("/***************success zuul 6001 启动成功******************/"); } @Bean public TokenFilter tokenFilter() { return new TokenFilter(); } }
配置文件:
spring: application: name: spring-cloud-zuul-002 server: port: 6001 eureka: client: service-url: defaultZone: http://localhost:7001/eureka zuul: retryable: false routes: producer: path: /api1/** serviceId: spring-cloud-producter1-002 baidu: path: /bd/** url: http://www.baidu.com
filter:token拦截
public class TokenFilter extends ZuulFilter{ private Logger logger= LoggerFactory.getLogger(TokenFilter.class); @Override public String filterType() { return "pre"; // 可以在请求被路由之前调用 } @Override public int filterOrder() { // filter执行顺序,通过数字指定 ,优先级为0,数字越大,优先级越低 return 0; } @Override public boolean shouldFilter() { // 是否执行该过滤器,此处为true,说明需要过滤 return true; } @Override public Object run() throws ZuulException { RequestContext ctx = RequestContext.getCurrentContext(); HttpServletRequest request = ctx.getRequest(); logger.info("--->>> TokenFilter {},{}", request.getMethod(), request.getRequestURL().toString()); String token = request.getParameter("token");// 获取请求的参数 if (StringUtils.isNotBlank(token)) { ctx.setSendZuulResponse(true); //对请求进行路由 ctx.setResponseStatusCode(200); ctx.set("isSuccess", true); return null; } else { ctx.setSendZuulResponse(false); //不对其进行路由 ctx.setResponseStatusCode(400); ctx.setResponseBody("token is empty"); ctx.set("isSuccess", false); return null; } } }
FallbackProvider
@Component public class ProviderFallBack implements FallbackProvider{ private Logger logger= LoggerFactory.getLogger(ProviderFallBack.class); //指定要处理的 service。 @Override public String getRoute() { // api服务id,如果需要所有调用都支持回退,则return "*"或return null return "spring-cloud-producter2-002"; } /** * 如果请求用户服务失败,返回什么信息给消费者客户端 */ @Override public ClientHttpResponse fallbackResponse(String route, Throwable cause) { return new ClientHttpResponse() { /** * 网关向api服务请求是失败了,但是消费者客户端向网关发起的请求是OK的, * 不应该把api的404,500等问题抛给客户端 * 网关和api服务集群对于客户端来说是黑盒子 */ @Override public HttpStatus getStatusCode() throws IOException { return HttpStatus.OK; } @Override public int getRawStatusCode() throws IOException { return 200; } @Override public String getStatusText() throws IOException { return "ok"; } @Override public void close() { } @Override public InputStream getBody() throws IOException { logger.info("/***********获取getBody *******************/"); Map r = new HashMap(); r.put("state", "9999"); r.put("msg", "系统错误,请求失败"); //返回异常信息 return new ByteArrayInputStream("The service is unavailable.".getBytes("UTF-8")); } @Override public HttpHeaders getHeaders() { HttpHeaders headers = new HttpHeaders(); //和body中的内容编码一致,否则容易乱码 // headers.setContentType(MediaType.APPLICATION_JSON); headers.setContentType(MediaType.APPLICATION_JSON_UTF8); return headers; } }; } }
内容比较多我们现在开始测试讲解
测试过程
启动zuul服务后,我们同样访问注册中心页面,发现已注册成功。
1. token认证实现:
在我们构建接口的时候往往会有认证,此时怎么实现呢?
结合 filter:token拦截 代码(需要注册成组件,在启动类或者加注解可以)
我们可以看到程序对参数进行了token参数值的一个获取,很简单,验证是否为空即可(一般放在header里进行传递,有不明白的可以留言)
要是没有token会怎样呢?服务进行拦截,不再进行转发到生产者
无token访问
有token访问
2.测试一中spring-cloud-producter1-002?这个是啥
解答:zuul路由注册到注册中心后通过服务的名称是可以直接调用生产者的,也就是spring-cloud-producter1-002是生产者1的名称
3.换种访问方式,猜猜api1是什么?
我们可以看到测试1中返回的结果是一样的,自然api1就代表着生产者1的服务
在zuul的配置文件中指定即可
访问百度的时候 localhost:6001/bd?token=1 也是可以跳转的。
4.重点
一、zuul:开启重试机制
pom引入
<dependency> <groupId>org.springframework.retry</groupId> <artifactId>spring-retry</artifactId> </dependency>
配置文件可以配置如下重试策略(结合文档看)
二、api服务网关zuul回退fallback hystrix有fallback回退能力,及如果服务调用出现了异常,则执行指定的fallback方法。
zuul对api服务集群进行了反向代理,集成了hystrix,那zuul也能fallback了。
我们访问生产者2
为什么或这样,可以看到信息是在ProviderFallBack类定义的,说明生产者2没有调通,所有zuul回退返回了上面信息
生产者2controller如下:sleep很长时间,所以zuul调用超时,触发回退机制
End:
zuul的讲解就结束了,比较简单,但是很重要!很重要!智能路由在服务中发挥着直观重要的作用
我们现在zuul换成了spring cloud gateway,正在不断地开发新的功能,关于gateway的相关知识我们会用很多篇介绍也是整个微服务课程的重点(主要着做智能路由这块业务),有机会会开源相关插件,供大家参考
回到原点,即使springcloud不打算集成zuul2.x,但是简单了解下,面试或者工作还是有好处的,你说对吧?
编程之路期待你的参与 ,欢迎小伙伴加入 @架构师速成记
下载:https://github.com/shinians/springcloud-demos
来源:CSDN
作者:十年呵护
链接:https://blog.csdn.net/zzhuan_1/article/details/85954418