Zuul微服务网关、容错与监控、Zuul路由端点、路由配置、Zuul上传文件、Zuul过滤器、Zuul异常处理、Zuul回退、Zuul聚合微服务
一、为什么要使用微服务网关
二、Zuul
1、编写Zuul微服务网关
2、Zuul的Hystrix容错与监控
3、Zuul的路由端点
4、路由配置
1.自定义指定微服务的访问路径
2.忽略指定微服务
3.忽略所有微服务,只路由指定微服务
4.同时指定微服务的serviceId和对应路径
5.同时指定path和URL
6.使用正则表达式指定Zuul的路由匹配规则
7.路由前缀
8.忽略某些路径
5、Zuul的安全与Header
1.指定敏感Header
2.忽略Header
6、Zuul上传文件
7、Zuul过滤器
1.编写Zuul过滤器
2.Zuul异常处理过滤器
3.Zuul默认过滤器
8、Zuul回退
9、Zuul聚合微服务
一、为什么要使用微服务网关
不同的微服务一般会经过不同的网络地址,而外部客户端可能需要调用多个服务的接口才能完成一个业务需求。
如果让客户端直接与各个微服务通信,会有以下的问题:
- 客户端会多次请求不同的微服务,增加了客户端的复杂性。
- 存在跨域请求,在一定场景下处理相对复杂。
- 认证复杂,每个服务都需要独立认证。
- 难以重构,随着项目的迭代,可能需要重新划分微服务。例如,可能将多个服务整个成一个或者将一个服务拆分成多个。如果客户端直接与微服务通信,那么重构将会很难实施。
- 某些微服务可能使用了防火墙/浏览器不友好协议,直接访问会有一定的困难。
以上问题可借助微服务网管解决。微服务网关是介于客户端和服务器之间的中间层,所有外部请求都会先经过微服务网关。使用微服务网关后架构演变为下图。
如图,微服务网关封装了应用程序的内部结构,客户端只需跟网关交互,而无需直接调用特定微服务的接口。这样,开发就可以简化。不仅如此,使用微服务网关还有以下优点:
- 易于监控。可在微服务网关收集监控数据并将其推送到外部系统进行分析。
- 易于认证。可在微服务网关上进行认证,然后再将请求转发到后端的微服务,而无需再每个微服务中进行认证。
- 减少了客户端与各个微服务之间的交互次数。
二、Zuul
Zuul是Netflix开源的微服务网关,核心是一系列的过滤器,这些过滤器可以完成以下功能。
- 身份认证与安全:识别每个资源的验证需求,并拒绝那些与要求不符的请求。
- 审查与监控:在边缘位置追踪有意义的数据和统计结果,从而带来精确的生产视图。
- 动态路由:动态地请求路由到不同的后端集群。
- 压力测试:逐渐增加执行集群的流量,以了解性能。
- 负载分配:为每一种负载类型分配对应容量,并弃用超出限定值的请求。
- 静态响应处理:在边缘位置直接建立部分响应,从而避免其转发到内部集群。
- 多区域弹性:跨越AWS Region进行请求路由,旨在实现ELB(Elastic Load Balancing)使用多样化,以及让系统的边缘更贴近系统的使用者。
1、编写Zuul微服务网关
1.创建项目gateway-zuul
以下是pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.1.6.RELEASE</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.springclouddemo</groupId><artifactId>gateway-zuul</artifactId><version>0.0.1-SNAPSHOT</version><name>gateway-zuul</name><description>微服务网关</description><properties><java.version>1.8</java.version><spring-cloud.version>Greenwich.SR1</spring-cloud.version></properties><dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-zuul</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies><dependencyManagement><dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>${spring-cloud.version}</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>
2.编写application配置文件
spring.application.name=gateway-zuul
server.port=7400
eureka.client.service-url.defaultZone=http://localhost:7000/eureka/
eureka.instance.prefer-ip-address=true
3.在main类添加@EnableZuulProxy注解
package com.springclouddemo.gatewayzuul;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;/*** @author 何昌杰*/
@SpringBootApplication
@EnableZuulProxy
public class GatewayZuulApplication {public static void main(String[] args) {SpringApplication.run(GatewayZuulApplication.class, args);}}
这样一个简单的微服务网关就搭建成功了,并且将这个微服务注册到Eureka Server上。
测试:
- 启动项目eureka-server、gateway-zuul、eureka-client-provider、eureka-client-consumer-feign
- 访问http://localhost:7400/eureka-client-consumer-feign/hello/hcj,请求就会转发到http://localhost:7204/hello/hcj上
- 访问http://localhost:7400/eureka-client-provider/hello/hcj,请求就会转发到http://localhost:7100/hello/hcj上
默认情况下Zuul会代理所有注册到Eureka Server的微服务,并且Zuul的路由规则是:http://ZUUL_HOST:ZUUL_PORT/微服务名称/**会转发到对应的微服务上。
2、Zuul的Hystrix容错与监控
Zuul是默认继承了负载均衡和熔断的,负载均衡无需任何操作,Greenwich版本的Hystrix需要添加@Bean配置路径才可以访问/hystrix.stream
将项目gateway-zuul的main类修改如下:
package com.springclouddemo.gatewayzuul;import com.netflix.hystrix.contrib.metrics.eventstream.HystrixMetricsStreamServlet;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
import org.springframework.context.annotation.Bean;/*** @author 何昌杰*/
@SpringBootApplication
@EnableZuulProxy
public class GatewayZuulApplication {public static void main(String[] args) {SpringApplication.run(GatewayZuulApplication.class, args);}@Beanpublic ServletRegistrationBean getServlet() {HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet();ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet);registrationBean.setLoadOnStartup(1);registrationBean.addUrlMappings("/hystrix.stream");registrationBean.setName("HystrixMetricsStreamServlet");return registrationBean;}
}
测试:
- 启动项目eureka-server、gateway-zuul、eureka-client-provider、eureka-client-consumer-feign
- 分别访问http://localhost:7400/eureka-client-consumer-feign/hello/hcj,http://localhost:7400/eureka-client-provider/hello/hcj
- 访问http://localhost:7400/hystrix.stream,可以得到如下内容
说明Zuul已经整合了Hystrix(默认整合)。
3、Zuul的路由端点
当@EnableZuulProxy与Spring Boot Actuator配合使用时,Zuul会暴露一个路由管理端点/actuator/routes(低版本为/routes端点)。借助这个端点,可以方便、直观地查看以及管理Zuul的路由。
/actuator/routes端点的使用非常简单,使用GET方法访问端点,即可以返回Zuul当时映射的路由列表;使用POST方式访问该端点就会强制刷新Zuul当时映射的路由列表(尽管路由会自动刷新,Spring Cloud依然提供了强制立即刷新的方式)。
由于spring-cloud-starter-netflix-zuul已经包含了spring-boot-starter-actuator,因此之前编写的gateway-zuul项目已经具备路由管理的能力,不过需要在application配置文件中添加以下配置。
management.endpoints.web.exposure.include=routes
访问http://localhost:7400/actuator/routes,可以看到以下内容:
4、路由配置
某些场景写我们只想让Zuul代理部分微服务,或者需要对URL进行更加精确的控制。
1.自定义指定微服务的访问路径
配置zuul.routes,指定微服务的serviceId=指定路径 即可:
zuul.routes.eureka-client-consumer-feign=/feign/**
这样配置,eureka-client-consumer-feign微服务就会被映射到/feign/**路径。
2.忽略指定微服务
zuul.ignored-services=eureka-client-provider,eureka-client-consumer-feign
这样配置,Zuul就会忽略eureka-client-provider,eureka-client-consumer-feign微服务,只代理其他微服务。
3.忽略所有微服务,只路由指定微服务
某些场景下我们只想让Zuul代理指定微服务:
zuul.ignored-services='*'
zuul.routes.eureka-client-consumer-feign=/feign/**
这样配置,Zuul就会只路由eureka-client-consumer-feign这个微服务。
4.同时指定微服务的serviceId和对应路径
zuul.routes.feign.service-id=eureka-client-consumer-feign
zuul.routes.feign.path=/feign/**
- zuul.routes.feign.***的feign只是一个路由名称,可以任意修改名称
5.同时指定path和URL
zuul.routes.feign.service-id=http://localhost:7204/
zuul.routes.feign.path=/feign/**
zuul.routes.feign.***的feign只是一个路由名称,可以任意修改名称
6.使用正则表达式指定Zuul的路由匹配规则
借助PatternServiceRouteMapper,实现微服务的映射路由的正则配置:
package com.springclouddemo.gatewayzuul;import com.netflix.hystrix.contrib.metrics.eventstream.HystrixMetricsStreamServlet;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
import org.springframework.cloud.netflix.zuul.filters.discovery.PatternServiceRouteMapper;
import org.springframework.context.annotation.Bean;/*** @author 何昌杰*/
@SpringBootApplication
@EnableZuulProxy
public class GatewayZuulApplication {public static void main(String[] args) {SpringApplication.run(GatewayZuulApplication.class, args);}@Beanpublic ServletRegistrationBean getServlet() {HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet();ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet);registrationBean.setLoadOnStartup(1);registrationBean.addUrlMappings("/hystrix.stream");registrationBean.setName("HystrixMetricsStreamServlet");return registrationBean;}@Beanpublic PatternServiceRouteMapper serviceRouteMapper(){return new PatternServiceRouteMapper("(?<name>^.+)-(?<version>.+$)","${version}/${name}");}
}
通过上述配置可以实现eureka-client-consumer-feign这个微服务,映射到/feign/eureka-client-consumer/**这个路径。
7.路由前缀
zuul.routes.eureka-client-consumer-feign.path=/feign/**
zuul.routes.eureka-client-consumer-feign.strip-prefix=false
这样访问Zuul的/hello/**路径,请求就会被转发到eureka-client-consumer-feign的/hello/**上。
8.忽略某些路径
某些场景下我们想让Zuul代理某些微服务,同时又想保护该微服务的某些敏感路径,我们可以使用
zuul.ignored-patterns=/**/user/**
这样配置就是可以忽略微服务中所有包含/admin/的路径
5、Zuul的安全与Header
1.指定敏感Header
一般情况下同一个系统的服务之间共享Header,不过应尽量防止让一些敏感的Header外泄。因此,在很多场景下,需要通过为路由指定一系列敏感Header列表。
zuul.routes.eureka-client-consumer-feign.path=/feign/**
zuul.routes.eureka-client-consumer-feign.sensitive-headers=Cookie,Set-Cookie,Authorization
这样配置就可以为eureka-client-consumer-feign指定微服务访问路径和指定敏感Header
也可以全局指定敏感Header:
zuul.sensitive-headers=Cookie,Set-Cookie,Authorization
2.忽略Header
可以通过zuul.ignored-headers属性指定需要忽略的Header。
zuul.ignored-headers=Authorization
这样配置后Authorization将不会传播到其他的微服务中。
zuul.ignored-headers的默认值为空值,但如果Spring Security在项目的classpath中,那么zuul.ignored-headers的默认值就是Pragma,Cache-Control,X-Frame-Options,X-Content-Type-Options,X-XSS-Protection,Expires。所以当Spring Security在项目的classpath中,同时又需要使用下游微服务的Spriing Security的Header时,可以将zuul.ignore-security-headers设置为false。
6、Zuul上传文件
对于大文件(10M以上)上传,需要为上传路径添加/zuul前缀。也可以使用zuul.servlet-path自定义前缀。
例如假如zuul.routes.eureka-client-consumer-feign-upload=/upload/**,http://localhost/{HOST}:{PORT}/upload是微服务eureka-client-consumer-feign-upload的上传路径,则需要用Zuul的/zuul/upload路径进行上传(添加/zuul前缀)。
如果Zuul使用了Ribbon负载均衡,name对于超大文件,需要扩大超时设置:
(Hystrix与Ribbon的默认请求超时时间都是1秒)
hystrix.command.connect.execution.isolation.thread.timeoutInMilliseconds=60000
ribbon.connectTimeout=3000
ribbon.readTimeout=60000
还需要为提供上传文件的微服务添加以下配置:
(max-file-size默认1MB,max-request-size默认10MB)
spring.servlet.multipart.max-file-size=2000MB
spring.servlet.multipart.max-request-size=2500MB
7、Zuul过滤器
Zuul大部分功能都是通过过滤器来实现的,Zuul定义了4种标准的过滤器类型,这些过滤器类型对应于请求的典型生命周期。
- pre: 这种过滤器在请求被路由之前调用。可利用这种过滤器实现身份验证、在集群中选择请求的微服务,记录调试信息等。
- routing: 这种过滤器将请求路由到微服务。这种过滤器用于构建发送给微服务的请求,并使用apache httpclient或netflix ribbon请求微服务。
- post: 这种过滤器在路由到微服务以后执行。这种过滤器可用来为响应添加标准的http header、收集统计信息和指标、将响应从微服务发送给客户端等。
- error: 在其他阶段发送错误时执行该过滤器。
除了默认的过滤器类型,zuul还允许创建自定义的过滤器类型。例如,可以定制一种static类型的过滤器,直接在zuul中生成响应,而不将请求转发到后端的微服务。
Zuul请求的生命周期如下图,该图详细描述了各种类型的过滤器的执行顺序。
也可通过查看源码中com.netflix.zuul.http.ZuulServlet类的service了解执行顺序。
1.编写Zuul过滤器
1.复制项目gateway-zuul为gateway-zuul-filter
2.端口修改为7401,微服务名修改为gateway-zuul-filter
3.编写自定义Zuul过滤器filters/PreRequestLogFilter.java
package com.springclouddemo.gatewayzuulfilter.filters;import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;import javax.servlet.http.HttpServletRequest;/*** @author 何昌杰*/
@Component
public class PreRequestLogFilter extends ZuulFilter {private static final Logger log= LoggerFactory.getLogger(PreRequestLogFilter.class);@Overridepublic String filterType() {return "pre";}@Overridepublic int filterOrder() {return 1;}@Overridepublic boolean shouldFilter() {return true;}@Overridepublic Object run() throws ZuulException {RequestContext ctx = RequestContext.getCurrentContext();HttpServletRequest request = ctx.getRequest();log.info("send {} request to {}",request.getMethod(),request.getRequestURL());return null;}
}
- filterType 指定过滤器类型,对应上文几种过滤器
- filterOrder 指定过滤器执行顺序(默认越小越先执行)
- shouldFilter 是否启用该过滤器(true为启用,false为禁用)
- run 过滤器的具体业务逻辑
测试:
- 启动项目gateway-zuul-filter、eureka-server、eureka-client-provider
- 访问http://localhost:7401/eureka-client-provider/hello/hcj,正常响应,gateway-zuul-filter控制台输出以下内容
2019-07-11 21:47:54.622 INFO 5128 --- [nio-7401-exec-4] c.s.g.filters.PreRequestLogFilter : send GET request to http://localhost:7401/eureka-client-provider/hello/hcj
说明我们的自定义Zuul过滤器正常运行。
2.Zuul异常处理过滤器
当zuul通过eureka调用一个不可用、不存在、宕机了的服务时,可能就会直接返回类似于这样的不友好的画面:
我们可以通过编写一个异常过滤器来处理这种情况:
package com.springclouddemo.gatewayzuulfilter.filters;import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.apache.http.HttpStatus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;/*** @author 何昌杰*/
@Component
public class ErrorFilter extends ZuulFilter {private static final Logger log = LoggerFactory.getLogger(ErrorFilter.class);@Overridepublic String filterType() {return "error";}@Overridepublic int filterOrder() {return -1;}@Overridepublic boolean shouldFilter() {return true;}@Overridepublic Object run() throws ZuulException {RequestContext ctx = RequestContext.getCurrentContext();HttpServletResponse response = ctx.getResponse();response.setStatus(HttpStatus.SC_NOT_FOUND);response.setContentType("application/json;charset=UTF-8");Throwable throwable = ctx.getThrowable();try (PrintWriter writer = response.getWriter()) {writer.print("{\"resultCode\":404,\"data\":null,\"cause\":\"" + throwable.getCause() + "\",\"message\":\"路由转发错误\"}");} catch (IOException e) {log.error("系统异常{}", e.getMessage());}return null;}
}
测试:
- 启动项目gateway-zuul-filter、eureka-server、eureka-client-provider
- 访问http://localhost:7401/eureka-client-provider/hello/hcj,正常响应
- 停止项目eureka-client-provider后再次访问http://localhost:7401/eureka-client-provider/hello/hcj,响应如下:
说明我们的异常处理过滤器正常运行。
3.Zuul默认过滤器
类型 | 顺序 | 过滤器 | 功能 |
---|---|---|---|
pre | -3 | ServletDetectionFilter | 标记处理Servlet的类型 |
pre | -2 | Servlet30WrapperFilter | 包装HttpServletRequest请求 |
pre | -1 | FormBodyWrapperFilter | 包装请求体 |
route | 1 | DebugFilter | 标记调试标志 |
route | 5 | PreDecorationFilter | 处理请求上下文供后续使用 |
route | 10 | RibbonRoutingFilter | serviceId请求转发 |
route | 100 | SimpleHostRoutingFilter | url请求转发 |
route | 500 | SendForwardFilter | forward请求转发 |
post | 0 | SendErrorFilter | 处理有错误的请求响应 |
post | 1000 | SendResponseFilter | 处理正常的请求响应 |
8、Zuul回退
想为Zuul添加回退需要实现FallbakcProvider接口,指定为哪些微服务提供回退并且提供一个ClientHTTPResponse作为回退响应。
1.复制项目gateway-zuul为gateway-zuul-fallback
2.端口修改为7402,微服务名修改为gateway-zuul-fallback
3.编写Zuul的回退类
package com.springclouddemo.gatewayzuulfallback.fallbacks;import org.springframework.cloud.netflix.zuul.filters.route.FallbackProvider;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.stereotype.Component;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;/*** @author 何昌杰*/
@Component
public class ProviderFallback implements FallbackProvider {@Overridepublic String getRoute() {return "*";}@Overridepublic ClientHttpResponse fallbackResponse(String route, Throwable cause) {return new ClientHttpResponse() {@Overridepublic HttpStatus getStatusCode() throws IOException {//fallback时的状态码return HttpStatus.OK;}@Overridepublic int getRawStatusCode() throws IOException{//数字类型的状态码return 200;}@Overridepublic String getStatusText() throws IOException{//状态文本return this.getStatusCode().getReasonPhrase();}@Overridepublic void close() {}@Overridepublic InputStream getBody() throws IOException{//响应体return new ByteArrayInputStream("此微服务不可用,请稍后重试!".getBytes());}@Overridepublic HttpHeaders getHeaders() {//响应头部HttpHeaders httpHeaders = new HttpHeaders();MediaType mediaType = new MediaType("application", "json", Charset.forName("UTF-8"));httpHeaders.setContentType(mediaType);return httpHeaders;}};}
}
- getRoute() 返回值指定微服务的serviceId,也可以是*代表所有微服务。
测试:
- 启动项目gateway-zuul-fallback、eureka-server、eureka-client-provider
- 访问http://localhost:7402/eureka-client-provider/hello/hcj,正常响应
- 停止项目eureka-client-provider后再次访问http://localhost:7402/eureka-client-provider/hello/hcj,响应如下:
说明我们为Zuul添加回退成功。
9、Zuul聚合微服务
在很多次场景下,外部请求需要查询Zuul后端的多个微服务。举个例子,一个电影售票手机APP,在购票订单页上,既需要查询“电影微服务”获得电影相关信息,又需要查询“用户微服务”获得当前用户的信息。如果让手机端直接请求各个微服务(即使使用Zuul进行转发),那么网络开销、流量耗费、耗费时长可能都无法令人满意。那么对于这种场景,可使用Zuul聚合微服务请求——手机APP只需发送一个请求给Zuul,由于Zuul请求用户微服务以及电影微服务,并组织好数据给手机APP。
使用这种方式,手机端只须发送一次请求即可,简化了客户端侧的开发;不仅如此,由于Zuul、用户微服务、电影微服务一般都在同一局域网,因此速度非常快,效率会非常高。
下面围绕以上这个场景,来编写代码。
1.复制项目gateway-zuul为gateway-zuul-aggregation
2.将端口修改为7403,微服务名修改为gateway-zuul-aggregation
3.修改启动类
package com.springclouddemo.gatewayzuulaggregation;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;/*** @author 何昌杰*/
@SpringBootApplication
@EnableZuulProxy
public class GatewayZuulAggregationApplication {public static void main(String[] args) {SpringApplication.run(GatewayZuulAggregationApplication.class, args);}@Bean@LoadBalancedpublic RestTemplate restTemplate(){return new RestTemplate();}}
4.创建业务类services/AggregationService.java
package com.springclouddemo.gatewayzuulaggregation.services;import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import rx.Observable;/*** @author 何昌杰*/
@Service
public class AggregationService {@Autowiredprivate RestTemplate restTemplate;@HystrixCommand(fallbackMethod = "fallback")public Observable<String> helloDemo1(String name) {// 创建一个被观察者return Observable.create(observer -> {// 请求微服务1的/hello/{name}端点String res = restTemplate.getForObject("http://eureka-client-consumer-feign/hello/{name}", String.class, name);observer.onNext(res);observer.onCompleted();});}@HystrixCommand(fallbackMethod = "fallback")public Observable<String> helloDemo2(String name) {return Observable.create(syncOnSubscribe -> {// 请求微服务2的/hello/{name}端点String res = restTemplate.getForObject("http://eureka-client-consumer-hystrix/hello/{name}", String.class, name);syncOnSubscribe.onNext(res);syncOnSubscribe.onCompleted();});}public String fallback(String name) {return "默认值:"+name;}}
5.创建controllers/AggregationController.java
在Controller中聚合多个请求
package com.springclouddemo.gatewayzuulaggregation.controllers;import com.google.common.collect.Maps;
import com.springclouddemo.gatewayzuulaggregation.services.AggregationService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.async.DeferredResult;
import rx.Observable;
import rx.Observer;import java.util.HashMap;/*** @author 何昌杰*/@RestController
public class AggregationController {public static final Logger LOGGER = LoggerFactory.getLogger(AggregationController.class);@Autowiredprivate AggregationService aggregationService;@GetMapping("/aggregate/{name}")public DeferredResult<HashMap<String, String>> aggregate(@PathVariable String name) {Observable<HashMap<String, String>> result = this.aggregateObservable(name);return this.toDeferredResult(result);}public Observable<HashMap<String, String>> aggregateObservable(String name) {// 合并两个或者多个Observables发射出的数据项,根据指定的函数变换它们return Observable.zip(this.aggregationService.helloDemo1(name),this.aggregationService.helloDemo1(name),(res1, res2) -> {HashMap<String, String> map = Maps.newHashMap();map.put("microservice1", res1);map.put("microservice2", res2);return map;});}public DeferredResult<HashMap<String, String>> toDeferredResult(Observable<HashMap<String, String>> details) {DeferredResult<HashMap<String, String>> result = new DeferredResult<>();// 订阅details.subscribe(new Observer<HashMap<String, String>>() {@Overridepublic void onCompleted() {LOGGER.info("完成...");}@Overridepublic void onError(Throwable throwable) {LOGGER.error("发生错误...", throwable);}@Overridepublic void onNext(HashMap<String, String> movieDetails) {result.setResult(movieDetails);}});return result;}
}
测试:
- 启动项目gateway-zuul-aggregation、eureka-server、eureka-client-provider、eureka-client-consumer-feign、eureka-client-consumer-hystrix
- 访问http://localhost:7403/aggregate/hcj,响应如下
控制台输出:
2019-07-11 22:56:53.639 INFO 5448 --- [nio-7403-exec-1] c.s.g.controllers.AggregationController : 完成...
- 停止项目eureka-client-provider、eureka-client-consumer-feign、eureka-client-consumer-hystrix后再次访问http://localhost:7403/aggregate/hcj,响应如下:
控制台输出:
2019-07-11 23:03:58.003 INFO 5448 --- [io-7403-exec-10] c.s.g.controllers.AggregationController : 完成...
说明我们已经成功用Zuul聚合了两个微服务的接口。
Zuul微服务网关、容错与监控、Zuul路由端点、路由配置、Zuul上传文件、Zuul过滤器、Zuul异常处理、Zuul回退、Zuul聚合微服务相关推荐
- nginx 限制文件上传速度_nginx上传文件速度慢 Nginx上传文件全部缓存解决方案 - 硬件设备 - 服务器之家...
nginx上传文件速度慢 Nginx上传文件全部缓存解决方案 发布时间:2017-03-09 来源:服务器之家 下面通过文字说明给大家详解Nginx上传文件全部缓存解决方案. 因为应用服务器(Jett ...
- Zuul上传文件,中文文件名乱码解决办法
问题描述 在项目中又一个上传文件的oss服务,直接调用服务的上传文件成功,如果经过网关zuul服务,上传中文名字的文件,文件名会出现乱码,最终导致上传失败,如果上传英文名字的文件,没有任何问题.怀疑网 ...
- 关于Spring Cloud Zuul网管上传文件乱码问题
Spring Cloud Zuul现在对于上传文件有两种处理方式,一种是用spring mvc,另一种是zuulServlet.spring mvc对文件处理不是很好,会导致乱码问题,zuulServ ...
- 通过Zuul上传文件,禁用Zuul的Filters
microservice-file-uploadspring:application:name: microservice-file-uploadhttp:multipart:max-file-siz ...
- 腾讯对象存储服务COS加密签名上传文件与下载文件的剖析,福利提供给所有使用Android的小伙伴们!
在做一些用户需求的时候,公司往往需要工程师采集到更多有用的关于用户的个人信息,然后对用户群进行分析,今天我不是来分析这些的,今天我主要是说 腾讯推出的款云产品,那就是对象存储服务COS,这个产品面向所 ...
- httpclient通过POST来上传文件,而不是通过流的形式,并在服务端进行解析(通过htt......
为什么80%的码农都做不了架构师?>>> package url;import io.IoStreamUtil;import java.io.File; import java ...
- android显示服务器端文件夹,Android上传文件到服务端并显示进度条
最近在做上传文件的服务,简单看了网上的教程.结合实践共享出代码. 由于网上的大多数没有服务端的代码,这可不行呀,没服务端怎么调试呢. Ok,先上代码. Android 上传比较简单,主要用到的是 Ht ...
- 第三方服务整合-阿里云OSS上传文件-填坑
目录 如下,引入aliyun-oss失败: 原因: 解决方法 OssController 如下,引入aliyun-oss失败: com.alibaba.cloud:aliyun-oss-spring- ...
- 开发者说:如何使用插件降低上传文件部署服务的复杂度
" 这里描述我们实际服务部署的时候频繁发生的两个常用场景. 第一个场景,我们"办公网环境"想要在"准生产环境"下部署,需要做如下工作: 打包.将文件上 ...
最新文章
- LeetCode简单题之距离顺序排列矩阵单元格
- linux安装mysql8.0_Linux系统:centos7下安装Jdk8、Tomcat8、MySQL5.7环境
- 史上最全提升GPU的tricks合集
- freeredius3.0 mysql_EDIUS非线性编辑系统价格,4k视频编辑系统
- Android TextView滚动的两种方案
- vc无法连接的原因分析
- 二相步进电机和三相步进电机有什么区别?
- Android 打开URL
- VMS-B230/260如何登录存储控制器
- 《黑马》——C++核心编程
- JavaScript实现大数据(条形统计图表)
- 厦门大学计算机保研学校,厦门大学计算机科学系(专业学位)计算机技术保研
- windows10安装keras教程
- 好用看得见!深度操作系统Deepin装机使用体验
- Digital Ocean 如何使用GitHub学生优惠码
- 深度强化学习(DRL)一:入门篇
- FOJ 1021 飞船赛
- 软件着作权转让交税如何缴纳
- freemarker将xml转为html,Freemarker 实现Html 静态化
- 幼儿园连锁管理系统源码 此源码已测试过,可正常运行 代码测试完整,界面漂亮,多套皮肤供选择
热门文章
- 谈谈自己对目前新型冠状病毒疫情的想法
- seamle***dp+rdesktop完美结合
- 交易系统五:海龟交易法
- 快速梳理23种常用的设计模式
- 利用随机森林对特征重要性进行评估 方法一
- python随机森林特征重要性原理_随机森林进行特征重要性度量的详细说明
- office365服务器没有响应,Win10安装Office365时电脑无响应的原因和解决方案
- java面试(二十五)--(1)redis为什么读写速率快性能好(2)说说web.xml文件中可以配置哪些内容(3)和的区别(4)扑克牌顺子
- zabbix邮件报警发送至qq邮箱
- 《前方的路》读书笔记