建企业网站建设注意问题,游戏制作软件免费下载,常见的导航网站有哪些,以家为主题做网站Zuul的核心是一系列的过滤器#xff0c;这些过滤器可以完成以下功能#xff1a; 身份认证与安全#xff1a;识别每个资源的验证要求#xff0c;并拒绝那些与要求不符的请求。审查与监控#xff1a;在边缘位置追踪有意义的数据和统计结果#xff0c;从而带来精确的生成视图…Zuul的核心是一系列的过滤器这些过滤器可以完成以下功能 身份认证与安全识别每个资源的验证要求并拒绝那些与要求不符的请求。审查与监控在边缘位置追踪有意义的数据和统计结果从而带来精确的生成视图。动态路由动态地将请求路由到不同的后端集群。压力测试逐渐增加执行集群的流量以了解性能。负载分配为每一种负载类型分配对应容量并弃用超出限定值得请求。静态响应处理在边缘位置直接建立部分响应从而避免其转发到内部集群。多区域弹性跨越AWS Region进行请求路由旨在实现ELBElastic Load Balancing)使用的多样化以及让系统的边缘更贴近系统的使用者。在实现了请求路由功能后我们的微服务应用提供的接口就可以通过统一的API网关入口被客户端访问到了。但是每个客户端用户请求为服务器应用提供的接口时它们的访问权限往往都有一定的限制系统并不会将所有的微服务接口都对它们开放。在完成了服务路由之后我们对外开放服务还需要一些安全措施来保护客户端只能访问它应该访问到的资源。所以我们需要利用Zuul的过滤器来实现我们对外服务的安全控制。 在服务网关中定义过滤器只需要继承ZuulFilter抽象类实现其定义的四个抽象函数就可对请求进行拦截与过滤。 比如下面的例子定义了一个Zuul过滤器实现了在请求被路由之前检查请求中是否有accessToken参数若有就进行路由若没有就拒绝访问返回401 Unauthorized错误。 package com.dxz.zuul;import javax.servlet.http.HttpServletRequest;import org.apache.log4j.Logger;import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;public class AccessFilter extends ZuulFilter {private static Logger log Logger.getLogger(AccessFilter.class);Overridepublic String filterType() {return pre;}Overridepublic int filterOrder() {return 0;}Overridepublic boolean shouldFilter() {return true;}Overridepublic Object run() {RequestContext ctx RequestContext.getCurrentContext();HttpServletRequest request ctx.getRequest();log.info(String.format(%s request to %s, request.getMethod(), request.getRequestURL().toString()));Object accessToken request.getParameter(accessToken);if (accessToken null) {log.warn(access token is empty);ctx.setSendZuulResponse(false);ctx.setResponseStatusCode(401);return null;}log.info(access token ok);return null;}} 在启动类里为自定义过滤器创建具体的Bean才能启动该过滤器如下 Beanpublic AccessFilter accessFilter() {return new AccessFilter();} 启动该服务网关后访问 http://127.0.0.1:5555/api-b/add?a1b5sn1返回401错误http://127.0.0.1:5555/api-b/add?a1b5sn1accessTokentoken正确路由到server并返回计算内容不可访问情况 可访问情况 过滤器 过滤器两个功能1、其中路由功能负责将外部请求转发到具体的微服务实例上是实现外部访问统一入口的基础2、过滤器功能则负责对请求的处理过程进行预干预是实现请求校验、服务聚合等功能的基础。 ZuulFilter抽象类 有4类可重写的方法来自定义过滤器如下 filterType返回一个字符串代表过滤器的类型在zuul中定义了四种不同生命周期的过滤器类型具体如下自定义过滤器的实现需要继承ZuulFilter需要重写实现下面四个方法 pre可以在请求被路由之前调用routing在路由请求时候被调用post在routing和error过滤器之后被调用error处理请求时发生错误时被调用filterOrder通过int值来定义过滤器的执行顺序shouldFilter返回一个boolean类型来判断该过滤器是否要执行所以通过此函数可实现过滤器的开关。在上例中我们直接返回true所以该过滤器总是生效。run过滤器的具体逻辑。需要注意这里我们通过ctx.setSendZuulResponse(false)令zuul过滤该请求不对其进行路由然后通过ctx.setResponseStatusCode(401)设置了其返回的错误码当然我们也可以进一步优化我们的返回比如通过ctx.setResponseBody(body)对返回body内容进行编辑等。 请求生命周期 对于其他一些过滤类型这里就不一一展开了根据之前对filterType生命周期介绍可以参考下图去理解并根据自己的需要在不同的生命周期中去实现不同类型的过滤器。 Zuul大部分功能都是通过过滤器来实现的这些过滤器类型对应于请求的典型生命周期 PRE 这种过滤器在请求被路由之前调用。我们可利用这种过滤器实现身份验证、在集群中选择请求的微服务、记录调试信息等。ROUTING这种过滤器将请求路由到微服务。这种过滤器用于构建发送给微服务的请求并使用Apache HttpClient或Netfilx Ribbon请求微服务。POST这种过滤器在路由到微服务以后执行。这种过滤器可用来为响应添加标准的HTTP Header、收集统计信息和指标、将响应从微服务发送给客户端等。ERROR在其他阶段发生错误时执行该过滤器。 除了默认的过滤器类型Zuul还允许我们创建自定义的过滤器类型。例如我们可以定制一种STATIC类型的过滤器直接在Zuul中生成响应而不将请求转发到后端的微服务。在完成了pre类型的过滤器处理之后请求进入第二个阶段routing也就是之前说的路由请求转发阶段请求将会被routing类型过滤器处理这里的具体处理内容就是将外部请求转发到具体服务实例上去的过程当服务实例将请求结果都返回之后routing阶段完成请求进入第三个阶段post此时请求将会被post类型的过滤器进行处理这些过滤器在处理的时候不仅可以获取到请求信息还能获取到服务实例的返回信息所以在post类型的过滤器中我们可以对处理结果进行一些加工或转换等内容。 另外还有一个特殊的阶段error该阶段只有在上述三个阶段中发生异常的时候才会触发但是它的最后流向还是post类型的过滤器因为它需要通过post过滤器将最终结果返回给请求客户端实际实现上还有一些差别后续介绍。 核心过滤器 在Spring Cloud Zuul中为了让API网关组件可以更方便的上手使用它在HTTP请求生命周期的各个阶段默认地实现了一批核心过滤器它们会在API网关服务启动的时候被自动地加载和启用。我们可以在源码中查看和了解它们它们定义于spring-cloud-netflix-core模块的org.springframework.cloud.netflix.zuul.filters包下。 如上图所示在默认启用的过滤器中包含了三种不同生命周期的过滤器这些过滤器都非常重要可以帮助我们理解Zuul对外部请求处理的过程以及帮助我们如何在此基础上扩展过滤器去完成自身系统需要的功能。下面我们将逐个地对这些过滤器做一些详细的介绍 pre过滤器 ServletDetectionFilter它的执行顺序为-3是最先被执行的过滤器。该过滤器总是会被执行主要用来检测当前请求是通过Spring的DispatcherServlet处理运行还是通过ZuulServlet来处理运行的。 它的检测结果会以布尔类型保存在当前请求上下文的isDispatcherServletRequest参数中这样在后续的过滤器中我们就可以通过RequestUtils.isDispatcherServletRequest()和RequestUtils.isZuulServletRequest()方法判断它以实现做不同的处理。 一般情况下发送到API网关的外部请求都会被Spring的DispatcherServlet处理除了通过/zuul/路径访问的请求会绕过DispatcherServlet被ZuulServlet处理主要用来应对处理大文件上传的情况。另外对于ZuulServlet的访问路径/zuul/我们可以通过zuul.servletPath参数来进行修改。 Servlet30WrapperFilter它的执行顺序为-2是第二个执行的过滤器。目前的实现会对所有请求生效主要为了将原始的HttpServletRequest包装成Servlet30RequestWrapper对象。FormBodyWrapperFilter它的执行顺序为-1是第三个执行的过滤器。 该过滤器仅对两种类请求生效第一类是Content-Type为application/x-www-form-urlencoded的请求第二类是Content-Type为multipart/form-data并且是由Spring的DispatcherServlet处理的请求用到了ServletDetectionFilter的处理结果。 而该过滤器的主要目的是将符合要求的请求体包装成FormBodyRequestWrapper对象。 DebugFilter它的执行顺序为1是第四个执行的过滤器。 该过滤器会根据配置参数zuul.debug.request和请求中的debug参数来决定是否执行过滤器中的操作。而它的具体操作内容则是将当前的请求上下文中的debugRouting和debugRequest参数设置为true。 由于在同一个请求的不同生命周期中都可以访问到这两个值所以我们在后续的各个过滤器中可以利用这两值来定义一些debug信息这样当线上环境出现问题的时候可以通过请求参数的方式来激活这些debug信息以帮助分析问题。 另外对于请求参数中的debug参数我们也可以通过zuul.debug.parameter来进行自定义。 PreDecorationFilter它的执行顺序为5是pre阶段最后被执行的过滤器。该过滤器会判断当前请求上下文中是否存在forward.to和serviceId参数如果都不存在那么它就会执行具体过滤器的操作如果有一个存在的话说明当前请求已经被处理过了因为这两个信息就是根据当前请求的路由信息加载进来的。 而它的具体操作内容就是为当前请求做一些预处理比如进行路由规则的匹配、在请求上下文中设置该请求的基本信息以及将路由匹配结果等一些设置信息等这些信息将是后续过滤器进行处理的重要依据我们可以通过RequestContext.getCurrentContext()来访问这些 信息。 另外我们还可以在该实现中找到一些对HTTP头请求进行处理的逻辑其中包含了一些耳熟能详的头域比如X-Forwarded-Host、X-Forwarded-Port。 另外对于这些头域的记录是通过zuul.addProxyHeaders参数进行控制的而这个参数默认值为true所以Zuul在请求跳转时默认地会为请求增加X-Forwarded-*头域包括X-Forwarded-Host、X-Forwarded-Port、X-Forwarded-For、X-Forwarded-Prefix、X-Forwarded- Proto。 我们也可以通过设置zuul.addProxyHeadersfalse关闭对这些头域的添加动作。 route过滤器 RibbonRoutingFilter它的执行顺序为10是route阶段第一个执行的过滤器。该过滤器只对请求上下文中存在serviceId参数的请求进行处理即只对通过serviceId配置路由规则的请求生效。而该过滤器的执行逻辑就是面向服务路由的核心它通过使用Ribbon和Hystrix来向服务实例发起请求并将服务实例的请求结果返回。SimpleHostRoutingFilter它的执行顺序为100是route阶段第二个执行的过滤器。该过滤器只对请求上下文中存在routeHost参数的请求进行处理即只对通过url配置路由规则的请求生效。而该过滤器的执行逻辑就是直接向routeHost参数的物理地址发起请求从源码中我们可以知道该请求是直接通过httpclient包实现的而没有使用Hystrix命令进行包装所以这类请求并没有线程隔离和断路器的保护。 知道配置类似zuul.routes.user-service.urlhttp://localhost:8080/这样的底层都是通过httpclient直接发送请求的也就知道为什么这样的情况没有做到负载均衡的原因所在。 SendForwardFilter它的执行顺序为500是route阶段第三个执行的过滤器。该过滤器只对请求上下文中存在forward.to参数的请求进行处理即用来处理路由规则中的forward本地跳转配置。post过滤器 SendErrorFilter它的执行顺序为0是post阶段第一个执行的过滤器。该过滤器仅在请求上下文中包含error.status_code参数由之前执行的过滤器设置的错误编码并且还没有被该过滤器处理过的时候执行。而该过滤器的具体逻辑就是利用请求上下文中的错误信息来组织成一个forward到API网关/error错误端点的请求来产生错误响应。SendResponseFilter它的执行顺序为1000是post阶段最后执行的过滤器。该过滤器会检查请求上下文中是否包含请求响应相关的头信息、响应数据流或是响应体只有在包含它们其中一个的时候就会执行处理逻辑。而该过滤器的处理逻辑就是利用请求上下文的响应信息来组织需要发送回客户端的响应内容。下表是对上述过滤器根据顺序、名称、功能、类型做了综合的整理可以帮助我们在自定义过滤器或是扩展过滤器的时候用来参考并全面地考虑整个请求生命周期的处理过程。 Zuul中默认实现的Filter 类型顺序过滤器功能pre-3ServletDetectionFilter标记处理Servlet的类型pre-2Servlet30WrapperFilter包装HttpServletRequest请求pre-1FormBodyWrapperFilter包装请求体route1DebugFilter标记调试标志route5PreDecorationFilter处理请求上下文供后续使用route10RibbonRoutingFilterserviceId请求转发route100SimpleHostRoutingFilterurl请求转发route500SendForwardFilterforward请求转发post0SendErrorFilter处理有错误的请求响应post1000SendResponseFilter处理正常的请求响应禁用指定的Filter 可以在application.yml中配置需要禁用的filter格式 zuul:FormBodyWrapperFilter:pre:disable: true Zuul中的Filter执行顺序控制 1、定义是给出执行顺序 ZuulFilter抽象类实现了Comparable接口并实现了compareTo方法(zuul-core-1.3.0.jar的ZuulFilter.java) public int compareTo(ZuulFilter filter) {return Integer.compare(this.filterOrder(), filter.filterOrder());} 2、Filter执行是按照顺序执行 zuul-core-1.3.0.jar的FilterProcessor.java public Object runFilters(String sType) throws Throwable {if (RequestContext.getCurrentContext().debugRouting()) {Debug.addRoutingDebug(Invoking { sType } type filters);}boolean bResult false;ListZuulFilter list FilterLoader.getInstance().getFiltersByType(sType);if (list ! null) {for (int i 0; i list.size(); i) {ZuulFilter zuulFilter list.get(i);Object result processZuulFilter(zuulFilter);if (result ! null result instanceof Boolean) {bResult | ((Boolean) result);}}}return bResult;} zuul-core-1.3.0.jar的FilterLoader.java的getFilterByType中按类型pre、route、post取Filter后再按照FilterOrder进行排序。 public ListZuulFilter getFiltersByType(String filterType) {ListZuulFilter list hashFiltersByType.get(filterType);if (list ! null) return list;list new ArrayListZuulFilter();CollectionZuulFilter filters filterRegistry.getAllFilters();for (IteratorZuulFilter iterator filters.iterator(); iterator.hasNext(); ) {ZuulFilter filter iterator.next();if (filter.filterType().equals(filterType)) {list.add(filter);}}Collections.sort(list); // sort by priority
hashFiltersByType.putIfAbsent(filterType, list);return list;} zuul-core-1.3.0.jar的FilterProcessor.java的processZuulFilter方法执行具体Filter public Object processZuulFilter(ZuulFilter filter) throws ZuulException {RequestContext ctx RequestContext.getCurrentContext();boolean bDebug ctx.debugRouting();final String metricPrefix zuul.filter-;long execTime 0;String filterName ;try {long ltime System.currentTimeMillis();filterName filter.getClass().getSimpleName();RequestContext copy null;Object o null;Throwable t null;if (bDebug) {Debug.addRoutingDebug(Filter filter.filterType() filter.filterOrder() filterName);copy ctx.copy();}ZuulFilterResult result filter.runFilter();ExecutionStatus s result.getStatus();execTime System.currentTimeMillis() - ltime;switch (s) {case FAILED:t result.getException();ctx.addFilterExecutionSummary(filterName, ExecutionStatus.FAILED.name(), execTime);break;case SUCCESS:o result.getResult();ctx.addFilterExecutionSummary(filterName, ExecutionStatus.SUCCESS.name(), execTime);if (bDebug) {Debug.addRoutingDebug(Filter { filterName TYPE: filter.filterType() ORDER: filter.filterOrder() } Execution time execTime ms);Debug.compareContextState(filterName, copy);}break;default:break;}if (t ! null) throw t;usageNotifier.notify(filter, s);return o;} catch (Throwable e) {if (bDebug) {Debug.addRoutingDebug(Running Filter failed filterName type: filter.filterType() order: filter.filterOrder() e.getMessage());}usageNotifier.notify(filter, ExecutionStatus.FAILED);if (e instanceof ZuulException) {throw (ZuulException) e;} else {ZuulException ex new ZuulException(e, Filter threw Exception, 500, filter.filterType() : filterName);ctx.addFilterExecutionSummary(filterName, ExecutionStatus.FAILED.name(), execTime);throw ex;}}} 再调用ZuulFilter抽象类的runFilter()方法该方法执行子类自定义Filter的run方法完成我们的业务逻辑。 public ZuulFilterResult runFilter() {ZuulFilterResult zr new ZuulFilterResult();if (!isFilterDisabled()) {if (shouldFilter()) {Tracer t TracerFactory.instance().startMicroTracer(ZUUL:: this.getClass().getSimpleName());try {Object res run();zr new ZuulFilterResult(res, ExecutionStatus.SUCCESS);} catch (Throwable e) {t.setName(ZUUL:: this.getClass().getSimpleName() failed);zr new ZuulFilterResult(ExecutionStatus.FAILED);zr.setException(e);} finally {t.stopAndLog();}} else {zr new ZuulFilterResult(ExecutionStatus.SKIPPED);}}return zr;} 转载于:https://www.cnblogs.com/duanxz/p/7542150.html