一、为什么要使用微服务网关

二、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上。

测试:

  1. 启动项目eureka-server、gateway-zuul、eureka-client-provider、eureka-client-consumer-feign
  2. 访问http://localhost:7400/eureka-client-consumer-feign/hello/hcj,请求就会转发到http://localhost:7204/hello/hcj上
  3. 访问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;}
}

测试:

  1. 启动项目eureka-server、gateway-zuul、eureka-client-provider、eureka-client-consumer-feign
  2. 分别访问http://localhost:7400/eureka-client-consumer-feign/hello/hcj,http://localhost:7400/eureka-client-provider/hello/hcj
  3. 访问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 过滤器的具体业务逻辑

测试:

  1. 启动项目gateway-zuul-filter、eureka-server、eureka-client-provider
  2. 访问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;}
}

测试:

  1. 启动项目gateway-zuul-filter、eureka-server、eureka-client-provider
  2. 访问http://localhost:7401/eureka-client-provider/hello/hcj,正常响应
  3. 停止项目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,也可以是*代表所有微服务。

测试:

  1. 启动项目gateway-zuul-fallback、eureka-server、eureka-client-provider
  2. 访问http://localhost:7402/eureka-client-provider/hello/hcj,正常响应
  3. 停止项目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;}
}

测试:

  1. 启动项目gateway-zuul-aggregation、eureka-server、eureka-client-provider、eureka-client-consumer-feign、eureka-client-consumer-hystrix
  2. 访问http://localhost:7403/aggregate/hcj,响应如下

    控制台输出:

    2019-07-11 22:56:53.639  INFO 5448 --- [nio-7403-exec-1] c.s.g.controllers.AggregationController  : 完成...
  3. 停止项目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聚合微服务相关推荐

  1. nginx 限制文件上传速度_nginx上传文件速度慢 Nginx上传文件全部缓存解决方案 - 硬件设备 - 服务器之家...

    nginx上传文件速度慢 Nginx上传文件全部缓存解决方案 发布时间:2017-03-09 来源:服务器之家 下面通过文字说明给大家详解Nginx上传文件全部缓存解决方案. 因为应用服务器(Jett ...

  2. Zuul上传文件,中文文件名乱码解决办法

    问题描述 在项目中又一个上传文件的oss服务,直接调用服务的上传文件成功,如果经过网关zuul服务,上传中文名字的文件,文件名会出现乱码,最终导致上传失败,如果上传英文名字的文件,没有任何问题.怀疑网 ...

  3. 关于Spring Cloud Zuul网管上传文件乱码问题

    Spring Cloud Zuul现在对于上传文件有两种处理方式,一种是用spring mvc,另一种是zuulServlet.spring mvc对文件处理不是很好,会导致乱码问题,zuulServ ...

  4. 通过Zuul上传文件,禁用Zuul的Filters

    microservice-file-uploadspring:application:name: microservice-file-uploadhttp:multipart:max-file-siz ...

  5. 腾讯对象存储服务COS加密签名上传文件与下载文件的剖析,福利提供给所有使用Android的小伙伴们!

    在做一些用户需求的时候,公司往往需要工程师采集到更多有用的关于用户的个人信息,然后对用户群进行分析,今天我不是来分析这些的,今天我主要是说 腾讯推出的款云产品,那就是对象存储服务COS,这个产品面向所 ...

  6. httpclient通过POST来上传文件,而不是通过流的形式,并在服务端进行解析(通过htt......

    为什么80%的码农都做不了架构师?>>>    package url;import io.IoStreamUtil;import java.io.File; import java ...

  7. android显示服务器端文件夹,Android上传文件到服务端并显示进度条

    最近在做上传文件的服务,简单看了网上的教程.结合实践共享出代码. 由于网上的大多数没有服务端的代码,这可不行呀,没服务端怎么调试呢. Ok,先上代码. Android 上传比较简单,主要用到的是 Ht ...

  8. 第三方服务整合-阿里云OSS上传文件-填坑

    目录 如下,引入aliyun-oss失败: 原因: 解决方法 OssController 如下,引入aliyun-oss失败: com.alibaba.cloud:aliyun-oss-spring- ...

  9. 开发者说:如何使用插件降低上传文件部署服务的复杂度

    " 这里描述我们实际服务部署的时候频繁发生的两个常用场景. 第一个场景,我们"办公网环境"想要在"准生产环境"下部署,需要做如下工作: 打包.将文件上 ...

最新文章

  1. LeetCode简单题之距离顺序排列矩阵单元格
  2. linux安装mysql8.0_Linux系统:centos7下安装Jdk8、Tomcat8、MySQL5.7环境
  3. 史上最全提升GPU的tricks合集
  4. freeredius3.0 mysql_EDIUS非线性编辑系统价格,4k视频编辑系统
  5. Android TextView滚动的两种方案
  6. vc无法连接的原因分析
  7. 二相步进电机和三相步进电机有什么区别?
  8. Android 打开URL
  9. VMS-B230/260如何登录存储控制器
  10. 《黑马》——C++核心编程
  11. JavaScript实现大数据(条形统计图表)
  12. 厦门大学计算机保研学校,厦门大学计算机科学系(专业学位)计算机技术保研
  13. windows10安装keras教程
  14. 好用看得见!深度操作系统Deepin装机使用体验
  15. Digital Ocean 如何使用GitHub学生优惠码
  16. 深度强化学习(DRL)一:入门篇
  17. FOJ 1021 飞船赛
  18. 软件着作权转让交税如何缴纳
  19. freemarker将xml转为html,Freemarker 实现Html 静态化
  20. 幼儿园连锁管理系统源码 此源码已测试过,可正常运行 代码测试完整,界面漂亮,多套皮肤供选择

热门文章

  1. 谈谈自己对目前新型冠状病毒疫情的想法
  2. seamle***dp+rdesktop完美结合
  3. 交易系统五:海龟交易法
  4. 快速梳理23种常用的设计模式
  5. 利用随机森林对特征重要性进行评估 方法一
  6. python随机森林特征重要性原理_随机森林进行特征重要性度量的详细说明
  7. office365服务器没有响应,Win10安装Office365时电脑无响应的原因和解决方案
  8. java面试(二十五)--(1)redis为什么读写速率快性能好(2)说说web.xml文件中可以配置哪些内容(3)和的区别(4)扑克牌顺子
  9. zabbix邮件报警发送至qq邮箱
  10. 《前方的路》读书笔记