API网关服务:spring cloud zuul
路由
首先由两个服务: A , B
在网关yml中配置规则:
zuul.routes.A.path=/A/**
zuul.routes.A.serviceId=A
zuul.routes.B.path=/B/**
zuul.routes.B.serviceId=B
请求:http://localhost:5555/A/hello会被转发到A服务上
http://localhost:5555/B/hello会被转发到B服务上
请求过滤
自定义过滤器,需要继承ZuulFilter抽象类,并且实现它的四个抽象方法就行。
@Component public class MurphyTokenFilter extends ZuulFilter { @Autowired private IEsiAccountLoginService accountLoginService; @Value("${spring.redis.host}") private String redisHost; /*** * 过滤器类型,过滤器在哪个声明周期执行 * pre:请求被路由之前 * routing:在路由请求时调用 * post:在routing和error过滤器之后被调用 * error:处理请求发生错误时调用 * @return */ @Override public String filterType() { return "pre"; } /*** * 当有多个过滤器的时候,这个代表执行顺序,数值越小优先级越高 * @return */ @Override public int filterOrder() { return 10; } /*** * 判断过滤器是否被执行 * @return */ @Override public boolean shouldFilter() { return true; } /*** * 业务代码 * @return */ @Override public Object run() { RequestContext ctx = RequestContext.getCurrentContext(); ctx.setSendZuulResponse(false);//表示过滤掉该请求,不进行路由转发 ctx.setResponseStatusCode(Response.SC_UNAUTHORIZED);//返回错误码 ctx.setResponseBody(JSON.toJSONString("请求验证不通过,不进行转发")); ctx.getResponse().setContentType(CONTENT_TYPE_JSON); return false; } }
服务路由的默认规则
zuul会为每个服务默认维护一个路由规则:
但我们不希望所有服务都设置这种默认规则,所以可以做例外设置:
zuul.ignored-services=*
这样zuul对所有服务都不自动创建默认路由规则,这时就要在配置文件逐个为每个服务添加路由规则
路径匹配
路由匹配路径采用了ant的风格,有三种通配符
这时可能会遇到一种情况,一个url路径可能被多个不同表达式匹配上,比如有两个规则:
zuul.routes.user-service.path=/user-service/**
zool.routes.user-service.serviceId=user-service
zuul.routes.user-service-ext.path=/user-service/ext/**
zool.routes.user-service-ext.serviceId=user-service-ext
此时当调用/user-service/ext/**的时候两个路由规则都能匹配上。
做路由匹配的时候采用的线性遍历的方式,当获取到第一个匹配规则时就结束匹配,所以当有多个匹配规则匹配上时,根据规则的保存顺序只取第一个。
由于properties的配置内容无法保证有序,所以出现这种情况为了保证优先顺序,需要使用yml文件来配置,以实现有序的路由规则。
忽略表达式
zuul.ignored-patterns=/**/hello/**
zuul.routes.api-a.path=/api-a/**
zuul.routes.api-a.serviceId=hello-service
此时访问hello-service的hello接口时不通
Hystrix和ribbon的支持
过滤器详解
四种类型过滤器生命周期如图:
核心过滤器
在zuul启动的时候会默认开启一些核心过滤器
pre过滤器
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by Fernflower decompiler) // package org.springframework.cloud.netflix.zuul.filters.pre; import com.netflix.zuul.ZuulFilter; import com.netflix.zuul.context.RequestContext; import com.netflix.zuul.http.HttpServletRequestWrapper; import javax.servlet.http.HttpServletRequest; import org.springframework.web.servlet.DispatcherServlet; public class ServletDetectionFilter extends ZuulFilter { public ServletDetectionFilter() { } public String filterType() { return "pre"; } /*** * 第一个被执行 * @return */ public int filterOrder() { return -3; } public boolean shouldFilter() { return true; } /*** * 检查请求是通过spring的dispatcherServlet转发还是zuulServlet * @return */ public Object run() { RequestContext ctx = RequestContext.getCurrentContext(); HttpServletRequest request = ctx.getRequest(); if(!(request instanceof HttpServletRequestWrapper) && this.isDispatcherServletRequest(request)) { ctx.set("isDispatcherServletRequest", Boolean.valueOf(true));//dispatcherServlet } else { ctx.set("isDispatcherServletRequest", Boolean.valueOf(false));//zuulServlet } return null; } private boolean isDispatcherServletRequest(HttpServletRequest request) { return request.getAttribute(DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null; } }
Servlet30WrapperFilter:主要是将httpServletRequest对象转换成Servlet30RequestWrapper对象
FromBodyWrapperFilter:该过滤器只处理contentType为application/x-www-form-urlencoded和multipart/form-data的请求,并且必须是spirng servletDispathcer处理的请求。作用是将符合条件的请求体包装成FormBodyRequestWrapper对象。
DebugFilter:将debugRouting和debugRequest值设置为true
PreDecorationFilter:没看懂干嘛的
Routing过滤器
RibbonRoutingFilter:通过ribbon和hystrix向服务实例发起请求,并且返回结果
SimpleHostRoutingFilter:只对通过url配置路由规则的请求处理,直接向url的物理地址发起请求,通过httpclient没有使用hystrix,所以这类请求并没有线程隔离和断路器保护
Send'ForwardFilter:没看懂
Post过滤器
异常处理
保证所有代码都在try catch代码块内,当发生异常的时候:
ctx.setSendZuulResponse(false); ctx.setResponseStatusCode(Response.SC_UNAUTHORIZED); ctx.setResponseBody(JSON.toJSONString(CommonUtils.getFailResultBean(localMsg))); ctx.getResponse().setContentType(CONTENT_TYPE_JSON); return false;这样设置就能保证正常流转到SendErrorFilter处理异常信息返回。
但不能保证所有代码都在try catch中,所以当有异常抛出怎么办?定义error类型filter统一接受,然后再到SendErrorFilter
不足与优化
当在pre、routing中抛出异常的时候,会跳到error过滤器,error处理完会流转到post处理器做输出。但是当在post过滤器中抛出异常的时候,会跳到error处理器,error处理完后不会再跳到post过滤器了,没有post的处理输出,前端就看不到异常信息。这个问题该如何处理?
可以在errorFilter A之后再定义一个errorFilter B,B要继承SendErrorFilter,复用他的run方法,重写类型、执行顺序、shouldFilter,这样当postFilter抛出异常的时候到A,A处理完到B,B的作用和SendErrorFilter一样。
但又有个问题,上边的B应该是只处理PostFilter抛出的异常,如何在B中判断是PostFilter抛出的异常呢?也就是shouldFIlter应该怎么返回呢?
扩展过滤器,增加上下文属性。
zuul的核心处理器为FilterProcessor
最后在B的shouldFilter方法中可以拿到抛出异常的过滤器类型。
- Spring Cloud Zuul - API网关服务
- Spring Cloud中的API网关服务Zuul (13)
- 第二十一章 Spring CLoud Zuul使用 API 网关构建微服务
- 干货分享微服务spring-cloud(6.Api网关服务zuul)
- SpringCloud之API网关服务Spring Cloud Zuul实例
- 【微服务】之六:轻松搞定SpringCloud微服务-API网关zuul
- spring cloud Zuul(API网关服务)
- API网关服务:Spring Cloud Zuul
- spring cloud 使用Zuul 实现API网关服务问题
- SpringCloud API网关服务(Spring Cloud Zuul)
- SpringCloudAPI网关服务Zuul
- Spring Cloud入门教程(五):API服务网关(Zuul) 上
- Spring Boot + Spring Cloud 构建微服务系统(七):API服务网关(Zuul)
- SpringCloud调研系列5.2:服务网关Zuul组合API之Filter研究
- spring cloud+.net core搭建微服务架构:Api网关(三)
- SpringCloud的服务网关zuul
- 详解Spring Cloud Zuul 服务网关
- Spring Cloud Zuul 网关使用与 OAuth2.0 认证授权服务
- spring-cloud-zuul服务网关(五)
- Spring Cloud(六)服务网关 zuul 快速入门