🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
[TOC] # 简介 zuul的核心是一系列的过滤器,可以完成.核心功能是过滤和路由 * 身份认证与安全: 识别每个资源的验证要求,并拒绝哪些与要求不符的请求 * 审查与监控: 在边缘位置追踪有意义的数据和统计结果,从而带来精确的生产视图 * 动态路由: 动态的将请求路由到不同的后端集群 * 压力测试: 逐渐增加指向集群的流量,以了解性能 * 负载均衡: 为每一中负载类型分配对应容量,并弃用超出限定值的请求 * 静态响应处理: 在边缘位置直接建议部分响应,从而避免其转发到内部集群 * 多区域弹性: 跨越AWS Region进行请求路由,实现ELB(Elastic Load Balancing)使用的多样化,以及让系统的边缘更贴近系统的使用者 zuul目前默认使用的Http客户端是Apache Http Client,也可以使用RestClient或者okHttp3.OKHttpClient. 如果想使用RestClient,可以设置`ribbon.restclient.enabled=true` 想要使用okhttp3.OkHttpClient,可以设置`ribbon.okhttp.enabled=true` ![](https://img.kancloud.cn/90/68/9068a73f00908f7dc79d14a6394f3843_922x496.png) # 创建项目 idea`->` `new module` ~~~ <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-zuul</artifactId> </dependency> ~~~ ~~~ @EnableZuulProxy @SpringBootApplication public class GatewayApplication { public static void main(String[] args) { SpringApplication.run(GatewayApplication.class, args); } } ~~~ # 配置 ~~~ server: port: 10010 zuul: routes: hehe: path: /user-service/** url: http://0.0.0.0:8085/ ~~~ 这样写就是自己定义个规则 路径是user-service为前缀的所有,转发到`0.0.0.0:8085` **加入eureka** 加配置 ~~~ <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> ~~~ ~~~ eureka: client: service-url: defaultZone: http://127.0.0.1:10086/eureka zuul: routes: user-service: path: /user-service/** serviceId: user-service ~~~ 可以简化成 前面是服务名 ~~~ zuul: routes: user-service: /user/** ~~~ **默认的路由规则** 比如服务名是 `user_service`, 默认映射路径是 `user-service/**` 默认去eureka拉取,全部映射了 **禁用某个路由规则** ~~~ zuul: routes: user-service: /user/** ignored-services: - consumer-service ~~~ **路由前缀** 局部的 ~~~ zuul: routes: user-service: path: /user/** serviceId: user-service strip-prefix: false ~~~ 那这个url: [http://127.0.0.1:10010/user/user/1](http://127.0.0.1:10010/user/user/1) 就可以写成 [http://127.0.0.1:10010/user/1](http://127.0.0.1:10010/user/1) 就是这个前缀不去除,直接转发,那么重复的 user,就只写一个就行 全局的,一般是用来去除全局的prefix, 对局部没效果, 一般不用 ~~~ zuul: routes: user-service: /** strip-prefix: false prefix: /user # 配置前缀 ~~~ # 过滤器 zuul作为网关的一个重要功能, 就是实现请求鉴权. ## ZuulFilter 过滤器的顶级父类 ~~~ public abstract class ZuulFilter { abstract public String filterType(); // 过滤类型 abstract public int filterOrder(); //过滤顺序 boolean shouldFilter(); // IZuulFilter, 要不要过滤 Object run() throw ZuulException; // IZuulFilter, //过滤逻辑 ~~~ * shouldFilter: 返回一个Boolean值,判断该过滤器是否需要执行, 返回true执行 * run: 过滤器的具体业务逻辑 * filterType: 返回字符串,代表过滤类型,包含以下四种 - pre: 请求在被路由前执行 - routing: 在路由请求时调用 - post: 在routing和error过滤之后调用 - error: 处理请求时发生错误调用, 走完还会走post * filterOrder: 通过返回的int值来定义过滤器的执行顺序,数字越小优先级越高 ![](https://img.kancloud.cn/e9/75/e975876a279b86208656a34a4aa937d1_1308x796.png) `custom filters`: 自定义过滤器,可以在任何生命周期 **正常流程:** 请求到达先经过pre类型的过滤器, 而后到达routing类型, 进行路由, 请求就到达真正的服务提供者,执行请求,返回结果, 会到达post过滤器, 而后返回响应 **异常流程:** * 整个过程中, pre或者routing 过滤器出现异常, 都会直接进入error过滤器, 再error处理完毕后, 会将请求交给 post 过滤器, 最后返回给用户 * 如果是error过滤器自己出现异常, 最终也会进入post过滤器, 而后返回 * 如果是post过滤器出现异常,会跳转到error过滤器, 但是与pre和routing不同的是, 请求不会再到达post过滤器了 ## 自定义拦截器 需要用到的工具包 ~~~ <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> </dependency> ~~~ ~~~ package com.jdxia.filter; import com.netflix.zuul.ZuulFilter; import com.netflix.zuul.context.RequestContext; import com.netflix.zuul.exception.ZuulException; import org.apache.commons.lang3.StringUtils; import org.apache.http.HttpStatus; import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants; import org.springframework.stereotype.Component; import javax.servlet.http.HttpServletRequest; @Component public class LoginFilter extends ZuulFilter { //前置 @Override public String filterType() { return FilterConstants.PRE_TYPE; } //执行顺序,数字越小优先级越高 @Override public int filterOrder() { return FilterConstants.PRE_DECORATION_FILTER_ORDER - 1; } //是否需要执行, 返回true执行 @Override public boolean shouldFilter() { return true; } //逻辑 http://127.0.0.1:10010/user/user/1?access-token=123 @Override public Object run() throws ZuulException { //获取请求的上下文 Zuul包的 RequestContext ctx = RequestContext.getCurrentContext(); //获取请求参数 HttpServletRequest request = ctx.getRequest(); //判断是否存在 String token = request.getParameter("access-token"); //不存在, 未登入, 则拦截 StringUtils maven: org.apache.commons.lang3 if (StringUtils.isBlank(token)) { //拦截 ctx.setSendZuulResponse(false); //设置 返回403 ctx.setResponseStatusCode(HttpStatus.SC_FORBIDDEN); } return null; } } ~~~ # 负载均衡和熔断 zuul中默认集成了Ribbon负载均衡和Hystix熔断. 但是所有的超时策略都是走的默认值, 比如熔断超时时间只有1s,很容易就触发 建议手动配置 ~~~ hystrix: command: default: execution: isolation: thread: timeoutInMilliseconds: 6000 ribbon: ConnectionTimeOut: 500 ReadTimeOut: 1000 MaxAutoRetriesNextServer: 0 # 不重试 ~~~ ribbon超时 = (read + connect) * (重试) ribbon超时不能大于hystrix的 # zuul高可用 **额外** `spring-cloud-config`: 消息配置中心,自动去git拉取最新的配置,缓存.使用git的webhook钩子,去通知配置中心,说配置发生了变化,配置中心会通过消息总线去通知所有的微服务,更新配置 `spring-cloud-bus`: 消息总线 `spring-cloud-stream`: 消息总线 `spring-cloud-hystrix-dashboard`: 容错统计, 形成图形化界面 `spring-cloud-sleuth`: 链路追踪,结合Zipkin