服务网关: Spring Cloud Gateway前面已经介绍了基于Spring Cloud搭建微服务框架所需要的必需组件,利用这些组件再配合客户端就可以构建出一个完整的系统。但在实际应用场景中,每一个微服务都会部署到内网服务器中,或者禁止外部访问这些端口,这是对应用的一种安全保护机制。因此,我们如果想通过互联网来访问这些服务,需要一个统一的入口,这就是本章将介绍的微服务的又一大组件——服务网关。
我们需要服务网关,还有一些很重要的因素,比如服务网关会对接口进行统一拦截并做合法性校验,一个服务可以启动多个端口,利用服务网关进行负载均衡处理等。
目前市面上有很多产品可以实现服务网关这一功能,如 Nginx、Apache、Zuul以及 Spring CloudGateway等。Spring Cloud集成了Zuul和Gateway,我们可以很方便地实现服务网关这一功能。-gateway
Gateway简介关于Gateway,其官网是这样描述的:
This project provides a library for building an API Gateway on top of Spring MVC.Spring CloudGateway aims to provide a simple, yet effective way to route to APIs and provide cross cuttingconcerns to them such as: security, monitoring/metrics, and resiliency.-关
这个项目提供了一个在Spring MVC之上构建的API网关库,Spring Cloud Gateway致力于提供一个简单而有效的方法来由路由到API,并为它们提供跨领域的关注点,如安全、监控/度量和弹性。-gateway
Gateway是由Spring Cloud官方开发的一套基于WebFlux实现的网关组件,它的出现是为了替代Zuul。Gateway 不仅提供统一的路由方式,还基于Filter Chain供了网关的基本功能,例如安全、监控、埋点和限流等。-关
创建服务网关本节中,我们将开始创建服务网关,进一步优化我们的微服务架构。
(1)创建一个子工程,命名为gateway并添加以下依赖:
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId>< / dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-webflux</ artifactId></ dependency><dependency><artifactId>common</artifactId><groupId>com.lynn.blog</groupId><version>1.e-SNAPSHOT</version>< / dependency>前面提到,Spring Cloud Gateway基于WebFlux,因此需要添加 WebFlux依赖,注意不能引入Web依赖,否则无法正常启动gateway工程;此外,为了启用服务网关功能,还需要添加spring-cloud-starter-gateway依赖。-gateway
(2)在Git仓库创建一个配置文件gateway.yml,并添加以下内容:
server:port: 8088spring:application:name: gatewaycloud:#Spring Cloud Gateway路由配置方式gateway:#是否与服务发现组件进行结合,通过serviceId(必须设置成大写)转发到具体的服务实例。默认为false,设为true便开启通过服务中心的自动根据serviceId创建路由的功能discovery:#路由访问方式:配置的是服务网关日志策略。-关
(3)在gateway工程下创建bootstrap.yml配置文件,并添加以下内容:
spring:cloud :config:name: eurekaclient,gatewaylabel: masterdiscovery :enabled: trueserviceId: configusername: adminpassword: admineureka:client:serviceUrl:defaultzone: 配置,该配置内容如下:-gateway
spring:cloud:inetutils:preferred-networks : 127.0.e.1eureka:instance:prefer-ip-address: trueclient:register-with-eureka: truefetch-registry: true#开启熔断器feign:hystrix:enabled: true这些配置前面已经讲解,这里不再重复。-关
(4)创建应用启动类GatewayApplication,代码和前面讲的人口程序类似,此处省略具体的代码。
这样一个最简单的服务网关组件就搭建完成了。
接下来,分别启动register、config、test、 gateway工程并访问localhost:8080/TEST/test,如果出现如图9-1所示的内容,说明服务网关搭建成功。
在以上地址中,8080为网关启动端口,TEST为服务注册名 (Spring Cloud默认为大写),test为服务的restapi3地址。
利用过滤器拦截API请求使用服务网关还有一个很重要的原因是我们需要对外提供统一的统一过滤外来请求。
服务网关提供了多种过滤器( filter )供大家选择,如GatewayFilter和 GlobalFilter等,不同过滤器的作用是不一样的,GatewayFilter处理单个路由的请求,而GlobalFilter根据名字就能知道,它是一个全局过滤器,可以过滤所有路由请求。本文以全局过滤器GlobalFilter为例,讲解如何通过过滤器过滤API请求,达到鉴权的目的。-gateway
(1)创建ApiGlobalFilter类,并实现GlobalFilter:
@Componentpublic class ApiGlobalFilter implements GlobalFilter {@Overridepublic Mono<Void>filter(ServerwebExchange exchange,GatewayFilterChain chain){String token = exchange.getRequest().getQueryParams().getFirst("token");if ( StringUtils.isBlank( token)) iServer方法返回。-关
Spring Cloud Gateway依赖WebFlux,而WebFlux通过Mono对象返回数据,因此上述过滤器也返回了Mono对象。我们注意到,filter方法返回的是 Mono<Void>,读者可以将Void类理解为同Java的void关键字一样的功能,它其实就是void关键字的包装类,同int和 Integer的区别一样。该Mono并不返回任何数据,我们如果将它想象成普通的定义方法,就应该是void filter()。-gateway
(2)启动gateway 工程,访问localhost:8080/TEST/test,得到以下结果,如图9-2所示。说明全局过滤器对路由做了过滤处理。将地址加上 token参数后,将会得到如图9-1所示的结果。-关
请求失败处理如果要调用的服务出现异常或者宕机了,那么Gateway请求失败,必然会返回错误。这时停止 test工程并访问网关地址,可以看到如图9-3所示的界面。
这种500 错误对用户是不友好的,需要对服务网关进行统一的异常处理并给客户端返回统一的JSON数据,让客户端具有友好的体验,具体步骤如下。
(1)创建异常处理类JsonExceptionHandler,它继承自DefaultErrorwebExceptionHandler:
public class JsonExceptionHandler extends DefaultErrorwebExceptionHandler{public JsonExceptionHandler(ErrorAttributes errorAttributes,ResourcePropertiesresourceProperties, ErrorProperties errorProperties,ApplicationContextapplicationcontext) {super(errorAttributes,resourceProperties,errorProperties, applicationContext);)@overrideprotected Map<String, 0bject> getErrorAttributes(ServerRequest request,booleanincludeStackTrace) iint code = 508;Throwable error = super.getError(request);if (error instanceof org.springframework.cloud.gateway. support.NotFoundException){code = 404;}return response(code,this.buildMessage(request,error));}@overrideprotected RouterFunction<ServerResponse> getRoutingFunction(ErrorAttributeserrorAttributes) {return RouterFunctions.route(RequestPredicates.all(), this:: renderErrorResponse);}@overrideprotected 格式。-gateway
Spring Cloud Gateway进行异常处理的原理是,当出现请求服务失败(可以是服务不可用,也可以是路由地址404等)的情况,首先会调用getRoutingFunction方法,该方法接收ErrorAttributes对象,即接收具体的错误信息,然后调用getErrorAttributes方法获得异常属性,通过该方法判断具体的错误码,最终将错误信息放到Map 并返回客户端。-关
(2)覆盖默认异常,具体的实现如下:
@SpringBootConfiguration@EnableConfigurationProperties({ServerProperties.class,ResourceProperties.class})public class ErrorHandlerConfiguration {private final ServerProperties serverProperties;private final ApplicationContext applicationContext;private final ResourceProperties resourceProperties;private final List<ViewResolver> viewResolvers;private final ServerCodecConfigurer serverCodecconfigurer;public ErrorHandlerconfiguration(ServerProperties serverProperties,ResourceProperties resourceProperties,0bjectProvider<List<ViewResolver>>viewResolversProvider,ServerCodecConfigurer serverCodecConfigurer,Applicationcontext applicationcontext) {this.serverProperties = serverProperties;this.applicationContext = applicationContext;this.resourceProperties = resourceProperties;this.viewResolvers = viewResolversProvider.getIfAvailable(Collections: :emptyList);this.servercodecConfigurer = servercodecConfigurer;}@Bean@order(ordered.HIGHEST_PRECEDENCE)public ErrorwebExceptionHandler errorwebExceptionHandler(ErrorAttributeserrorAttributes) {JsonExceptionHandler exceptionHandler = new 3sonExceptionHandler(errorAttributes,this.resourceProperties,this.serverProperties.getError(),this.applicationContext);exceptionHandler.setViewResolvers(this.viewResolvers);exceptionHandler.setMessagewriters(this.serverCodecConfigurer.getwriters());exceptionHandler.setMessageReaders(this.serverCodecConfigurer.getReaders());return exceptionHandler;}}以上代码最核心的部分是errorlwebExceptionHandler方法,因此上述类添加了@SpringBoot-Configuration注解,并且 errorWwebExceptionHandler声明了@Bean。gateway工程启动时就会执行errorwebExceptionHandler方法且需要返回ErrorWwebExceptionHandler对象,方法内可以实例化sonExceptionHandler对象并返回。这样gateway在发生异常时就会自动执行JsonExceptionHandler而不会执行其默认类了。-gateway
(3)重新启动gateway并停止 test,访问地址 localhost:8080/TEST/test就可以得到如图9-4所示的结果。
小结本文介绍了Spring Cloud的另一大组件:服务网关,它是外部通信的唯一入口。在实际项目中,我们需要对接口进行安全性校验,而一套微服务架构可能存在成千上万个服务,不可能对每个服务都单独实现安全机制,而应通过服务网关统一拦截。Spring Cloud Gateway默认实现了负载均衡,一个服务可以部署到多台服务器,通过其负载均衡机制,.可以有效地提升系统的并发处理能力。-关
本文给大家讲解的内容是springcloud实战:服务网关,SpringCloudGateway下篇文章给大家讲解的是springcloud实战:网站功能开发;觉得文章不错的朋友可以转发此文关注小编;感谢大家的支持!-gateway