SpringCloud微服务就是把一个大的项目拆分红多个小的模块,而后模块之间经过远程调用、服务治理的技术互相配合工做,随着业务的增长,项目也将会愈来愈庞大,接口数量也随之增长,对外提供服务的接口也会增长,运维人员对于这些接口的管理也会变得愈来愈难。另外一方面对于一个系统来讲,权限管理也是一个不可少的模块,在微服务架构中,系统被拆分,不可能每一个模块都去添加一个个权限管理,这样系统代码重复、工做量大、后期维护也难。为了解决这些常见的架构问题,API网关应运而生。SpringCloudZuul是基于Netflix Zuul实现的API网关组件,它实现了请求路由、负载均衡、校验过滤、与服务治理框架的结合、请求转发是的熔断机制和服务的聚合等功能。
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-zuul</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> </dependency>
@EnableZuulProxy
注解开启API网关服务功能@SpringBootApplication @EnableZuulProxy public class ApigatewayApplication { public static void main(String[] args) { SpringApplication.run(ApigatewayApplication.class, args); } }
spring: application: name: api-gateway server: port: 8500 zuul: routes: # 面向服务的路由 api-a: path: /api-a/** serviceId: FEIGN-CONSUMER # 传统的路由 api-b-url: path: /api-b-url/** url: http://localhost:30000/ eureka: client: service-url: defaultZone: http://localhost:8888/eureka/
这里的代码是接着前面的,启动eureka-server、user-server、feign-consumer、article-server和api-gateway。我没添加了eureka的依赖,因此api-gateway也是服务提供方在注册中心注册:
而后访问http://localhost:8500/api-a/feign_consumer/find
和http://localhost:8500/api-b-url/a/u/1
java
在上面的配置文件文件中,使用两种路由规则的配置方法,一种是面向服务的,一种是使用传统的url。全部符合/api-a/**
的请求都将转发到feign-consumer,一样全部符合/api-b-url/**
的请求都将转发到http://localhost:30000/
,也就是前面使用的article-service。两种规则的配置很明显:面向服务的使用serviceId配置服务实例,而传统的直接使用服务的地址。git
前面也提到网关能够处理微服务的权限问题,在单体架构的时候咱们一般会使用拦截器或过滤器对请求进行权限的校验,一样在SpringCloudZuul中也提供了过滤器来进行请求的过滤与拦截,实现方法只要咱们继承抽象类ZuulFilter
并实现它定义的4个抽象方法。下面定义个拦截器来检查HttpServletRequest中是否带有accessToken参数程序员
AccessFilter
@Component public class AccessFilter extends ZuulFilter{ private static final Logger logger = LoggerFactory.getLogger(AccessFilter.class); @Override public String filterType() { return "pre"; } @Override public int filterOrder() { return 0; } @Override public boolean shouldFilter() { return true; } @Override public Object run() { RequestContext currentContext = RequestContext.getCurrentContext(); HttpServletRequest request = currentContext.getRequest(); logger.info("send{} request to {}",request.getMethod(),request.getRequestURI().toCharArray()); String accessToken = request.getParameter("accessToken"); if(StringUtils.isBlank(accessToken)){ logger.warn("accessToken is empty"); currentContext.setSendZuulResponse(false); currentContext.setResponseStatusCode(401); return null; } logger.info("accessToken {}" ,accessToken); return null; } }
上面说到咱们须要实现抽象类的ZuulFilter的四个抽象方法;spring
- filterType:过滤器类型,他决定过滤器在请求的哪一个生命周期执行。在Zuul中有四种不一样的生命周期过滤器:
- pre:能够在请求被路由以前调用; - routing:在路由请求是调用; - post:在routing和error过滤器以后被调用; - error:处理请求是发生错误是被调用
- filterOrder:过滤器的执行顺序,数值越小优先级越高
- shouldFilter:判断过滤器是否须要执行
- run: 过滤器的具体逻辑。上面的run方法中判断请求是否带有accessToken参数,若是没有则是非法请求,使用
currentContext.setSendZuulResponse(false);
表示该请求不进行路由。而后设置响应码。
请求的生命周期具体详解能够参考《SpringCloud微服务实战》api
在上面的配置中使用了zuul.toutes.<route>.path
和zuul.toutes.<route>.url
参数的方式配置单实例的路由,而在微服务架构中,为了服务的高可用,通常会将一个服务部署多个。传统的多实例的路由配置,Zuul提供了如下方法:架构
经过zuul.toutes.<route>.path
与zuul.toutes.<route>.serviceId
配置,以下:
zuul.routes.feign-consumer.path=/feign/**
zuul.routes.feign-consumer.serviceId=feign-consumer
robbin.eureka.enable=false
feign-consumer.ribbon.listOfServers=http://localhost:50000/,http://localhost:50001/
该配置实现了对符合/feign/**
规则的请求转发到http://localhost:50000/,http://localhost:50001/
两个实例地址的路由规则。这里的serviceId是有程序员手动命名的服务名称。robbin.eureka.enable=false
设置Ribbon不根据服务发现机制来获取配置服务对应的实例清单。app
zuul: routes: api-a: path: /api-a/** serviceId: feign-consumer
该配置实现了对符合/api-a/**
规则的请求路径转发到名为feign-consumer
的服务实例上去的路由规则。 api-a
是任意的路由名称。还可使用一种更加简洁的方法zuul.routes.<serviceId>=<path>
,这里serviceId指定具体的服务名,path配置匹配的请求表达式。负载均衡
通配符 | 含义 | url | 说明 |
---|---|---|---|
? | 匹配任意单个字符 | /feign/? | 匹配/feign/以后拼接一个任意字符的路径,如/feign/a |
* | 匹配任意数量的字符 | /feign/* | 匹配/feign/以后拼接任意字符的路径,如/feign/aaa |
** | 匹配任意数量的字符,支持多级目录 | /feign/** | 能够匹配/feign/*包含的内容以外,还可匹配形如/feign/a/b的多级目录 |
zuul.ignored-services=hello-service:
忽略掉一个服务;zuul.ignored-patterns=/**/feign/**:
忽略/feign接口路由;zuul.prefix:
为路由添加统一前缀;zuul.add-host-header: true:
在请求路由转发前为请求设置Host头信息;zuul.sensitiveHeaders=
:设置全局参数为空来覆盖默认敏感头信息zuul.routes.<route>.customSensitiveHeaders=true
:对指定路由开启自定义敏感头zuul.routes.<route>.sentiviteHeaders=
:将指定路由的敏感头设置为空。zuul.retryable=false
:关闭重试机制zuul.routes.<route>.retryable=false
:指定路由关闭重试机制zuul.<SimpleClassName>.<fileterType>.disable=true
:禁用指定的过滤器,<SimpleClassName>
表明过滤器的类名,<fileterType>
表明过滤器的类型。在Zuul中Hystrix和Ribbon的配置与传统的Hystrix和Ribbon服务的配置同样。框架
参考:《SpringCloud微服务实战》运维