路由是微服务架构不缺乏的一部分。例如“/”可能映射到web服务,“/api/users”映射到用户管理服务,而“/api/shop”映射到采购服务。Zuul是Netflix中的一个基于JVM的路由器,也是一个服务端负载均衡器。html
zuul有下列用途:java
注意:git
1)zuul.max.host.connections已经被zuul.host.maxTotalConnections(默认值200)和zuul.host.maxPerRouteConnections(默认值20)代替了。github
2)Hystrix对全部理由的默认隔离模式是SEMAPHORE,能够经过zuul.ribbonIsolationStrategy改成THREAD。web
1 <dependency> 2 <groupId>org.springframework.cloud</groupId> 3 <artifactId>spring-cloud-starter-netflix-zuul</artifactId> 4 </dependency>
Spring Cloud建立了一个内置Zuul代理来简化开发,好比有一个UI应用想要使用代理调用后端的一个或者多个服务。这能够避免为后台每一个服务都配置CORS和权限系统。正则表达式
在spring boot的入口类上使用@EnableZuulProxy注解来开启代理。代理使用Ribbon经过服务发现来定位后端服务实例。而且全部请求在 hystrix command中执行。因此当断路器打开时,代理将不会重试链接后端服务。spring
注意:Zuul starter不包含服务发现客户端,因此想要使用服务发现功能,须要提供一个服务发现客户端(好比Eureka)。后端
为了防止自动添加服务,能够设置zuul.ignored-services参数来避免。若是一个服务匹配到一个忽略表达式,而且又在路由映射中明确指定了,那么它就不会被忽略。例如(application.yml):api
1 zuul: 2 ignoredServices: '*' 3 routes: 4 users: /myusers/**
你能够单独指定路径和service ID,例如(application.yml):浏览器
1 zuul: 2 routes: 3 users: 4 path: /myusers/** 5 serviceId: users_service
其中path是一个ant风格的表达式,因此/myusers/*仅仅匹配一层目录,而/myusers/**能够匹配任意多层级目录。
其中后端服务的位置既可使用serviceId也可使用url(物理位置)指定。以下(application.yml):
1 zuul: 2 routes: 3 users: 4 path: /myusers/** 5 url: http://example.com/users_service
这些简单的url路由不会做为HystrixCommand执行,也不会使用Ribbon负载均衡。若是要使用的话,能够指定一个服务器列表的serviceId,以下:
application.yml.
1 zuul: 2 routes: 3 echo: 4 path: /myusers/** 5 serviceId: myusers-service 6 stripPrefix: true 7 8 hystrix: 9 command: 10 myusers-service: 11 execution: 12 isolation: 13 thread: 14 timeoutInMilliseconds: ... 15 16 myusers-service: 17 ribbon: 18 NIWSServerListClassName: com.netflix.loadbalancer.ConfigurationBasedServerList 19 listOfServers: http://example1.com,http://example2.com 20 ConnectTimeout: 1000 21 ReadTimeout: 3000 22 MaxTotalHttpConnections: 500 23 MaxConnectionsPerHost: 100
另外一个方法是指定一个服务路由而且为serviceId配置Ribbon客户端(这么作须要在Ribbon中禁用Eureka),以下:
application.yml.
1 zuul: 2 routes: 3 users: 4 path: /myusers/** 5 serviceId: users 6 7 ribbon: 8 eureka: 9 enabled: false 10 11 users: 12 ribbon: 13 listOfServers: example.com,google.com
可使用正则表达式来配置路由规则。以下:
ApplicationConfiguration.java.
1 @Bean 2 public PatternServiceRouteMapper serviceRouteMapper() { 3 return new PatternServiceRouteMapper( 4 "(?<name>^.+)-(?<version>v.+$)", 5 "${version}/${name}"); 6 }
在上面的例子中若是serviceId为myusers-v1那么它将被映射到/v1/myusers/**。若是有一个serviceId不匹配,那么将会使用默认规则。例如,在上面的例子中一个serviceId为myusers的服务将会映射到"/myusers/**"。
给全部映射添加前缀可使用zuul.prefix。默认状况下,请求被转发前将会去除掉其中的代理前缀(可使用zuul.stripPrefix=false来改变默认行为)。也能够在单独的一个路由中关闭去除服务指定前缀的行为。以下:
application.yml.
1 zuul: 2 routes: 3 users: 4 path: /myusers/** 5 stripPrefix: false
注意:zuul.stripPrefix只是针对zuul.prefix,对路由中的路径不起做用。
在上面的例子中/myusers/101请求将会转发为/myusers/101到users服务中。
zuul.routes是绑定在ZuulProperties对象上。在这个类里能够看到retryable属性,将它设置为true,能够在请求失败时使用Ribbon客户端重试。
默认状况下,X-Forwarded-Host将会添加到转发的请求头上,能够设置zuul.addProxyHeaders = false来关闭它。默认状况下,路径中的前缀将会被跳过,转发的请求头中将会有一个X-Forwarded-Prefix头(例如上面例子中的/myusers)。
注意:若是你但愿你配置的路由是有序的话,那你应该使用yml配置文件,由于使用properties文件时会丢失排序。
Zuul的默认HTTP客户端是Apache HTTP客户端而不是已通过时的Ribbon的RestClient。若是要使用RestClient或者okhttp3.OkHttpClient,能够设置ribbon.restclient.enabled=true
或者 ribbon.okhttp.enabled=true。
若是你想自定义Apache HTTP client 或者 OK HTTP client,那么须要提供一个ClosableHttpClient
或者 OkHttpClient类型的bean。
能够在路由配置中指定要忽略的头部,以下:
application.yml.
1 zuul: 2 routes: 3 users: 4 path: /myusers/** 5 sensitiveHeaders: Cookie,Set-Cookie,Authorization 6 url: https://downstream
注意:上面的例子是sensitiveHeaders的默认值,这是在Spring Cloud Netflix 1.1版本新增的功能。(在1.0中,不能设置头部而且全部cookie双向流动)。
sensitiveHeaders是一个黑名单,默认不为空。所以要让Zuul发送全部头部的话,须要明确指定sensitiveHeaders为空。以下:
application.yml.
1 zuul: 2 routes: 3 users: 4 path: /myusers/** 5 sensitiveHeaders: 6 url: https://downstream
你也能够经过zuul.sensitiveHeader进行全局设置。若是在一个路由上设置sensitiveHeaders的话将会覆盖全局设置。
除了路由敏感头部之外,你还能够设置zuul.ignoredHeaders成那些在与下游服务交互时应该剔除的值。默认,Spring Security不在classpath上时,这些值是空的。不然他们被Spring Security初始化为一些常见的“安全”头部。
这种状况下,下游的服务也可能设置这些头部,可是咱们想要的是代理中的值。若是Spring Security在classpath上时,为了避免剔除这些安全头部,能够设置zuul.ignoreSecurityHeaders=false。
若是你同时使用@EnableZuulProxy
和Spring Boot Actuator,那么将会开启两个额外的端点:
get请求/routes:
GET /routes.
1 { 2 /stores/**: "http://localhost:8081" 3 }
若是想要获得路由的详细信息,在请求上添加?format=details查询字段。
GET /routes/details
1 { 2 "/stores/**": { 3 "id": "stores", 4 "fullPath": "/stores/**", 5 "location": "http://localhost:8081", 6 "path": "/**", 7 "prefix": "/stores", 8 "retryable": false, 9 "customSensitiveHeaders": false, 10 "prefixStripped": true 11 } 12 }
/routes的POST方法将会强制刷新路由信息。
能够经过endpoints.routes.enabled=false来禁用这个端点。
注意:路由会自动根据服务目录的改动来更新,可是POST请求/routes是一种当即强制更新的方法。
/filters的GET请求将会返回过滤器类型列表。
当迁移一个老的应用或者API时,须要慢慢把它的访问端点替换成新的实现。Zuul会是一个颇有用的代理,由于你可使用它处理全部来自客户端老的端点的流量而且重定向一些请求到新的实现上。以下:
application.yml.
1 zuul: 2 routes: 3 first: 4 path: /first/** 5 url: http://first.example.com 6 second: 7 path: /second/** 8 url: forward:/second 9 third: 10 path: /third/** 11 url: forward:/3rd 12 legacy: 13 path: /** 14 url: http://legacy.example.com
其中,forward:开头的url将会转发到本地。
若是你使用@EnableZuulProxy,那么能够经过代理路径来上传一些小文件,对于大文件有一个能够绕过Spring DispatcherServlet的路径“/zuul/*”,换句话说,若是zuul.routes.customers=/customers/*,那么能够
经过发送POST请求到/zuul/customers/*。servlet路径是经过zuul.servletPath外部化的。若是代理路由使用Ribbon,尤为大文件须要提升超时时间。以下:
application.yml.
1 hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds: 60000 2 ribbon: 3 ConnectTimeout: 3000 4 ReadTimeout: 60000
当处理请求时,查询字段将会被解码,这样就能够在Zuul过滤器中修改他们。而后在过滤器中再从新编码后发送请求给后端。若是使用Javascrip的encodeURIComponent()方法,那么结果可能会和原始输入不一样。这在大多数状况下不会有问题,可是一些web服务器对于复杂查询字段的编码要求仍是很挑剔的。
为了强制查询字符串的原始编码,能够向ZuulProperties传递一个特殊的标志,以便将查询字符串做为HttpServletRequest::getQueryString方法使用。
application.yml.
1 zuul: 2 forceOriginalQueryStringEncoding: true
注意:这个特殊的标志只对SimpleHostRoutingFilter有效,另外能够经过RequestContext.getCurrentContext().setRequestQueryParams(someOverriddenParameters)来覆盖查询字符串。
若是使用@EnableZuulServer
(而不是@EnableZuulProxy),能够启动一个Zuul服务器可是没有任何代理。任何ZuulFilter类型的bean会自动安装,可是没有任何代理过滤器会被自动添加。
这种状况下,Zuul服务器的路由依然能够经过"zuul.routes.*"来配置,可是没有服务发现和代理。所以,"serviceId" 和 "url"会被忽略掉。在下面的例子中全部"/api/**"中的路径都会被映射到Zuul的过滤器链。
application.yml.
1 zuul: 2 routes: 3 api: /api/**
在代理和服务器模式,spring cloud Zuul都会默认注册一些ZuulFilter。能够经过zuul.<SimpleClassName>.<filterType>.disable=true来禁用指定的过滤器。
按照惯例,包名中filters的后面就是filterType。例如,若是要禁用org.springframework.cloud.netflix.zuul.filters.post.SendResponseFilter,能够设置zuul.SendResponseFilter.post.disable=true。
当Zuul的路由回路出现问题时,能够经过一个FallbackProvider类型的bean来提供降级服务。在这个bean中,须要指定路由的ID,而且提供一个ClientHttpResponse。下面的例子提供了一个相对简单的FallbackProvider的实现。
1 class MyFallbackProvider implements FallbackProvider { 2 3 @Override 4 public String getRoute() { 5 return "customers"; 6 } 7 8 @Override 9 public ClientHttpResponse fallbackResponse(String route, final Throwable cause) { 10 if (cause instanceof HystrixTimeoutException) { 11 return response(HttpStatus.GATEWAY_TIMEOUT); 12 } else { 13 return response(HttpStatus.INTERNAL_SERVER_ERROR); 14 } 15 } 16 17 private ClientHttpResponse response(final HttpStatus status) { 18 return new ClientHttpResponse() { 19 @Override 20 public HttpStatus getStatusCode() throws IOException { 21 return status; 22 } 23 24 @Override 25 public int getRawStatusCode() throws IOException { 26 return status.value(); 27 } 28 29 @Override 30 public String getStatusText() throws IOException { 31 return status.getReasonPhrase(); 32 } 33 34 @Override 35 public void close() { 36 } 37 38 @Override 39 public InputStream getBody() throws IOException { 40 return new ByteArrayInputStream("fallback".getBytes()); 41 } 42 43 @Override 44 public HttpHeaders getHeaders() { 45 HttpHeaders headers = new HttpHeaders(); 46 headers.setContentType(MediaType.APPLICATION_JSON); 47 return headers; 48 } 49 }; 50 } 51 }
下面的例子是对应上面例子的路由配置:
1 zuul: 2 routes: 3 customers: /customers/**
若是要对全部路由提供一个默认降级服务,能够建立一个FallbackProvider类型的bean,而后在getRoute方法中返回“*”或者null。以下:
1 class MyFallbackProvider implements FallbackProvider { 2 @Override 3 public String getRoute() { 4 return "*"; 5 } 6 7 @Override 8 public ClientHttpResponse fallbackResponse(String route, Throwable throwable) { 9 return new ClientHttpResponse() { 10 @Override 11 public HttpStatus getStatusCode() throws IOException { 12 return HttpStatus.OK; 13 } 14 15 @Override 16 public int getRawStatusCode() throws IOException { 17 return 200; 18 } 19 20 @Override 21 public String getStatusText() throws IOException { 22 return "OK"; 23 } 24 25 @Override 26 public void close() { 27 28 } 29 30 @Override 31 public InputStream getBody() throws IOException { 32 return new ByteArrayInputStream("fallback".getBytes()); 33 } 34 35 @Override 36 public HttpHeaders getHeaders() { 37 HttpHeaders headers = new HttpHeaders(); 38 headers.setContentType(MediaType.APPLICATION_JSON); 39 return headers; 40 } 41 }; 42 } 43 }
若是想要为经过Zuul代理的请求设置socket超时时间和读取超时时间,你有两个选项,基于配置:
1)若是Zuul使用服务发现,则配置ribbon.ReadTimeout和ribbon.SocketTimeout;
2)若是路由是经过URL指定的,那么须要配置zuul.host.connect-timeout-millis和zuul.host.socket-timeout-millis
Location
header(重写头部Location字段)若是Zuul在一个web应用前面,那么你须要重写Location头部当你的web应用经过HTTP状态码3XX重定向。不然,浏览器会重定向到web应用的URL而不是Zuul的URL。
能够经过配置一个LocationRewriteFilter类型的Zuul过滤器来重写Location头部到Zuul的URL。它还恢复了删除的全局前缀和特定于路由的前缀。以下:
1 import org.springframework.cloud.netflix.zuul.filters.post.LocationRewriteFilter; 2 ... 3 4 @Configuration 5 @EnableZuulProxy 6 public class ZuulConfig { 7 @Bean 8 public LocationRewriteFilter locationRewriteFilter() { 9 return new LocationRewriteFilter(); 10 } 11 }
注意:要很是当心使用这个过滤器,由于它会做用于全部响应码为3XX的Location头部,这可能在某些场合不适合。好比要重定向到一个外部地址。
Zuul在Actuator metrics端点下提供metrics,当路由请求出现失败时。能够经过/actuator/metrics端点查看。metrics名称的格式为ZUUL::EXCEPTION:errorCause:statusCode。
Zuul的实现是一个Servlet。一般状况下,Zuul是嵌入到Spring分发机制中的。Spring MVC会掌控路由。这种状况下,Zuul会缓存请求。若是有一种状况是穿过Zuul可是不要缓存(例如大文件的上传),这时可使用一种独立于Spring分发器的外部Servlet。默认状况,这个Servlet的地址是/zuul。也能够经过zuul.servlet-path属性来修改。
Zuul使用RequestContext在不一样的过滤器中传递信息。它的数据保存在特定于每一个请求的ThreadLocal中.它存储的信息有:路由请求到何处,错误,
HttpServletRequest
和 HttpServletResponse。
RequestContext继承ConcurrentHashMap,因此它能够存储任何信息。FilterConstants保存了那些被过滤器使用的key。
1.16.3 @EnableZuulProxy
vs. @EnableZuulServer
Spring Cloud Netflix安装了一系列过滤器,安装了哪些过滤器依赖于你使用哪一种注解来开启Zuul的。@EnableZuulProxy是@EnableZuulServer的超集。换句话说,@EnableZuulProxy包含了@EnableZuulServer中的过滤器。
在“proxy”模式中的额外过滤器开启了路由功能。因此若是想要一个“空白”的Zuul,就使用@EnableZuulServer。
1.16.4 @EnableZuulServer
Filters@EnableZuulServer建立一个SimpleRouteLocator(它从Spring Boot配置文件中加载路由定义)。
安装的过滤器(做为普通的spring bean):
1)Pre filters:
ServletDetectionFilter:检测请求是不是经过Spring Dispatcher,设置FilterConstants.IS_DISPATCHER_SERVLET_REQUEST_KEY的布尔值。
FormBodyWrapperFilter:解析表单数据,而且为下游请求从新编码这些数据。
DebugFilter:若是请求参数中设置了debug,则RequestContext.setDebugRouting()和RequestContext.setDebugRequest()都设置为true。
2)Route filters:
SendForwardFilter:使用RequestDispatcher转发请求。转发地址存储在RequestContext的FilterConstants.FORWARD_TO_KEY属性中。
3)Post filters:
SendResponseFilter:将代理请求的响应写入到当前的响应中。
4)Error filters:
SendErrorFilter:若是RequestContext.getThrowable()不是null,则转发到/error(默认)。也能够error.path设置转发路径。
1.16.5 @EnableZuulProxy
Filters建立一个 DiscoveryClientRouteLocator(从DiscoveryClient(例如Eureka)和配置文件中加载路由定义)。为每一个服务发现客户端中的serviceId都会建立一个路由。当有新服务添加时,路由就会刷新。
除了上面的过滤器外,还有额外的过滤器:
1)Pre filters:
PreDecorationFilter:根据提供的RouteLocator来决定如何路由,而且路由到何处。而且为下游服务设置了一些代理相关的头部。
2)Route filters:
RibbonRoutingFilter:使用Ribbon、Hystrix和可插入的HTTP客户端发送请求。服务ID存储在RequestContext的FilterConstants.SERVICE_ID_KEY键中。
这个过滤器可使用不一样的HTTP客户端:
1️⃣Apache HttpClient:默认客户端
2️⃣Squareup OkHttpClient
v3:添加com.squareup.okhttp3:okhttp依赖,而且设置ribbon.okhttp.enabled=true。
3️⃣Netflix Ribbon HTTP client:设置ribbon.restclient.enabled=true。可是这个客户端有一些限制,它不支持PATCH方法,可是有内建的重试机制。
SimpleHostRoutingFilter:经过Apache HttpClient向预约的url发送请求。URL在RequestContext.getRouteHost()中。
下面大多数的例子都包括在Sample Zuul Filters项目中。这个项目中还包含了一些若是修改请求或者响应的消息体的例子。
Pre filters为在RequestContext中设置数据,给下游的过滤器使用。主要用途就设置一些route过滤器须要的信息。以下:
1 public class QueryParamPreFilter extends ZuulFilter { 2 @Override 3 public int filterOrder() { 4 return PRE_DECORATION_FILTER_ORDER - 1; // run before PreDecoration 5 } 6 7 @Override 8 public String filterType() { 9 return PRE_TYPE; 10 } 11 12 @Override 13 public boolean shouldFilter() { 14 RequestContext ctx = RequestContext.getCurrentContext(); 15 return !ctx.containsKey(FORWARD_TO_KEY) // a filter has already forwarded 16 && !ctx.containsKey(SERVICE_ID_KEY); // a filter has already determined serviceId 17 } 18 @Override 19 public Object run() { 20 RequestContext ctx = RequestContext.getCurrentContext(); 21 HttpServletRequest request = ctx.getRequest(); 22 if (request.getParameter("sample") != null) { 23 // put the serviceId in `RequestContext` 24 ctx.put(SERVICE_ID_KEY, request.getParameter("foo")); 25 } 26 return null; 27 } 28 }
上面的过滤器使用sample请求参数填充SERVICE_ID_KEY。实际上不该该作这种直接映射,Service ID应该从sample的值中查找。
如今,SERVICE_ID_KEY已经被填充,因此PreDecorationFilter将不会执行,RibbonRoutingFilter会执行。
注意:若是想路由到一个完整的URL,调用ctx.setRouteHost(url)。
要修改路由过滤器转发到的路径,请设置REQUEST_URI_KEY。
Route filters在pre filters后执行。它转发请求到其余服务。这里的大部分工做是将请求和响应数据转换到客户机所需的模型。
1 public class OkHttpRoutingFilter extends ZuulFilter { 2 @Autowired 3 private ProxyRequestHelper helper; 4 5 @Override 6 public String filterType() { 7 return ROUTE_TYPE; 8 } 9 10 @Override 11 public int filterOrder() { 12 return SIMPLE_HOST_ROUTING_FILTER_ORDER - 1; 13 } 14 15 @Override 16 public boolean shouldFilter() { 17 return RequestContext.getCurrentContext().getRouteHost() != null 18 && RequestContext.getCurrentContext().sendZuulResponse(); 19 } 20 21 @Override 22 public Object run() { 23 OkHttpClient httpClient = new OkHttpClient.Builder() 24 // customize 25 .build(); 26 27 RequestContext context = RequestContext.getCurrentContext(); 28 HttpServletRequest request = context.getRequest(); 29 30 String method = request.getMethod(); 31 32 String uri = this.helper.buildZuulRequestURI(request); 33 34 Headers.Builder headers = new Headers.Builder(); 35 Enumeration<String> headerNames = request.getHeaderNames(); 36 while (headerNames.hasMoreElements()) { 37 String name = headerNames.nextElement(); 38 Enumeration<String> values = request.getHeaders(name); 39 40 while (values.hasMoreElements()) { 41 String value = values.nextElement(); 42 headers.add(name, value); 43 } 44 } 45 46 InputStream inputStream = request.getInputStream(); 47 48 RequestBody requestBody = null; 49 if (inputStream != null && HttpMethod.permitsRequestBody(method)) { 50 MediaType mediaType = null; 51 if (headers.get("Content-Type") != null) { 52 mediaType = MediaType.parse(headers.get("Content-Type")); 53 } 54 requestBody = RequestBody.create(mediaType, StreamUtils.copyToByteArray(inputStream)); 55 } 56 57 Request.Builder builder = new Request.Builder() 58 .headers(headers.build()) 59 .url(uri) 60 .method(method, requestBody); 61 62 Response response = httpClient.newCall(builder.build()).execute(); 63 64 LinkedMultiValueMap<String, String> responseHeaders = new LinkedMultiValueMap<>(); 65 66 for (Map.Entry<String, List<String>> entry : response.headers().toMultimap().entrySet()) { 67 responseHeaders.put(entry.getKey(), entry.getValue()); 68 } 69 70 this.helper.setResponse(response.code(), response.body().byteStream(), 71 responseHeaders); 72 context.setRouteHost(null); // prevent SimpleHostRoutingFilter from running 73 return null; 74 } 75 }
上面的过滤器将Servlet请求信息转换到OkHttp3请求信息中,而且发送一个HTTP请求,而后将OkHttp3响应信息转换到Servlet响应信息中。
Post filters主要是用来修改响应。下面的例子中在响应头中添加一个X-Sample头部而且设置为UUID。
1 public class AddResponseHeaderFilter extends ZuulFilter { 2 @Override 3 public String filterType() { 4 return POST_TYPE; 5 } 6 7 @Override 8 public int filterOrder() { 9 return SEND_RESPONSE_FILTER_ORDER - 1; 10 } 11 12 @Override 13 public boolean shouldFilter() { 14 return true; 15 } 16 17 @Override 18 public Object run() { 19 RequestContext context = RequestContext.getCurrentContext(); 20 HttpServletResponse servletResponse = context.getResponse(); 21 servletResponse.addHeader("X-Sample", UUID.randomUUID().toString()); 22 return null; 23 } 24 }
注意:其余操做,好比转换响应体,则要复杂得多,计算量也大得多。
Zuul过滤器的生命周期的任何阶段出现异常,error过滤器将会执行。当RequestContext.getThrowable()不为null时,SendErrorFilter将会执行。它而后在请求中设置javax.servlet.error.*属性,
而后将请求转发到spring boot的错误页面。
Zuul内部使用Ribbon来请求远程URL。默认,Ribbon客户端在第一次被使用时才被Spring Cloud加载。能够经过下面的配置来改变默认行为。它会在启动时初始化Ribbon相关的上下文。
application.yml.
1 zuul: 2 ribbon: 3 eager-load: 4 enabled: true
Spring Cloud Netflix提供了许多发送HTTP请求的方法。你可使用RestTemplate
, Ribbon, 或者 Feign。不管怎么选择建立HTTP请求,都有可能请求失败。
当请求失败时,你可能想要请求自动重试。当使用Sping Cloud Netflix时,你须要添加Spring Retry到classpath上。这样RestTemplates
, Feign, 和 Zuul会在请求失败时
自动重试。
默认,在使用重试机制时是没有补偿政策的。若是你想配置一个补偿政策,则须要建立一个LoadBalancedBackOffPolicyFactory类型的bean。它会为指定的服务建立一个BackOffPolicy。以下:
1 @Configuration 2 public class MyConfiguration { 3 @Bean 4 LoadBalancedBackOffPolicyFactory backOffPolicyFactory() { 5 return new LoadBalancedBackOffPolicyFactory() { 6 @Override 7 public BackOffPolicy createBackOffPolicy(String service) { 8 return new ExponentialBackOffPolicy(); 9 } 10 }; 11 } 12 }
当你使用Ribbon和Spring Retry时,你能够经过配置某些Ribbon属性来控制重试功能。例如,client.ribbon.MaxAutoRetries
, client.ribbon.MaxAutoRetriesNextServer
, 和 client.ribbon.OkToRetryOnAllOperations。
注意:开启client.ribbon.OkToRetryOnAllOperations的话将会包括重试POST请求,这样会对服务器资源有些影响,由于它会缓存请求体数据。
另外,你可能但愿对某些响应中的状态码进行重试请求。可经过设置clientName.ribbon.retryableStatusCodes。
1 clientName: 2 ribbon: 3 retryableStatusCodes: 404,502
你也能够建立一个LoadBalancedRetryPolicy类型的bean,而且实现retryableStatusCode方法。
能够经过zuul.retryable设置为false来关闭zuul中的重试机制。也能够设置zuul.routes.routename.retryable为false来关闭某个指定路由上的重试机制。
Spring Cloud Netflix 会为Ribbon, Feign, 和 Zuul自动建立HTTP客户端。你也能够提供你本身的HTTP客户端。若是您使用的是Apache Http Cient,那么能够建立类型为ClosableHttpClient的bean,或者若是您使用的是OK Http,则能够建立OkHttpClient。
注意:当您建立本身的HTTP客户机时,您还负责为这些客户机实现正确的链接管理策略。若是没作好会致使资源管理问题。