前面我们了解了springcloud 组件中的注册中心(eureka),负载均衡(ribbon),熔断器(hystrix),声明式服务调用(feign)等组件,有了这些组件我们已经基本可以搭建分布式服务框架了,我们通常会搭建如下的服务架构(手动画的图比较粗糙):

我们对外的服务会通过搭建一个openserver,一个RestFull 的api 给外部用户调用,并且通过F5或者nginx 进行负载均衡和路由。
我们可以考虑下实际当中运维和开发会遇到的一些问题,服务的ip,或者服务实例的增减,我们需要运维同事手动的去配置维护,需要维护一份配置表,让服务比较少的时候,暂且能够忍受,当服务集群规模越来越大的时候,这种维护工作对运维来说是一种灾难,并且维护带来的错误会呈现几何倍数增加。
还有对于开发来说,由于服务被拆分了,许多不同的服务实例都需要开发一套权限的校验逻辑,还有参数校验等逻辑,但其实这部分逻辑大家都是一样的,当这部分逻辑代码出现bug或者需要修改的时候,需要去修改所有的服务代码,这也是不可接受的,当然这也会加重测试同事的工作量。
为了解决上述大的问题,API网关的概念应运而生。他类似于设计模式中的Facade模式,他的存在就像是整个微服务架构的门面一样的存在,所有的外部客户请求调用的需要经过他的调度和过滤才会被路由到对应的服务进行执行请求。
springcloud 为我们提供了 springcloud zuul网关实现。他是基于netflix zuul的实现。首先如何解决路由规则和服务实例的维护问题,springcloud zuul 通过和springcloud eureka 整合实现,将自身注册为eureka 实例,这样他同时也获得了eureka 中的所有服务实例信息,这样就很巧妙的解决了维护服务实例信息问题,交由服务治理框架自动完成,不再需要人工干预,而对于路由规则,zuul 默认会将服务名作为ContextPath 的方式来创建路由映射,这样默认的配置已经解决了我们大部分的路由需求。
其次我们再来看看类似于签名校验,登陆验证等问题,这些都是调用微服务的一些前置校验,springcloud zuul提供了一套过滤器机制来实现请求的过滤。
下面我们来动手搭建网关服务:
pom:
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-zuul</artifactId></dependency>
springboot 启动类:
@EnableZuulProxy@SpringCloudApplicationpublic class ApiGatewayApplication {public static void main(String[] args) {SpringApplication.run(ApiGatewayApplication.class, args);}@Beanpublic AccessFilter initAccessFilter(){return new AccessFilter();}}
通过@EnableZuulProxy 开启zuul的API网关功能。
springboot配置文件:
spring.application.name=api-gatewayserver.port=8085eureka.client.service-url.defaultZone=http://localhost:8080/eureka
然后我们启动我们之前的eureka 服务注册中心,以及helloService,然后再启动我们的网关服务,并查看下控制台信息:

可以看到 网关服务也被作为一个服务注册到了eureka注册中心,下面我们来看看如何配置路由,我们可以通过服务名的方式进行路由配置:zuul.routes.<route>.path 和zuul.routes.<route>.serviceId 参数进行配置即可。
譬如:
zuul.routes.hello-api.path=/hello-api/**zuul.routes.hello-api.service-id=HELLOSERVICE#简化配置#****默认配置小坑,请求前缀为 serviceId 全部小写,切勿用eureka 注册中心服务名,因为是全部大写#zuul.routes.HELLOSERVICE=/hello-api/**
然后我们修改配置文件,然后进行访问测试:
访问:http://localhost:8085/hello-api/refact/hello1?name=ethan&accessToken=jjj
看到结果如图:

我们得到了预期的响应。这里注意一个小坑:
默认配置小坑,请求前缀为 serviceId 全部小写,切勿用eureka 注册中心服务名,因为是全部大写
但其实我们实际运用中,我们绝大部分情况,我们都会用服务名作为请求的前缀,这里其实zuul 为我们创建了默认的路由规则,这些默认规则的path会使用serviceId 配置作为请求前缀(serviceId 全部小写),这样通过整合eureka 轻松实现了路由的自动创建匹配是不是很666.
为了验证这个结论,我们注释掉上面的路由配置:
spring.application.name=api-gatewayserver.port=8085eureka.client.service-url.defaultZone = http://localhost:8070/eureka,http://localhost:8080/eureka#zuul.routes.hello-api.path=/hello-api/**#zuul.routes.hello-api.url=http://localhost:8081#zuul.routes.hello-api.path=/hello-api/**#zuul.routes.hello-api.service-id=HELLOSERVICE#简化配置#****默认配置小坑,请求前缀为 serviceId 全部小写,切勿用eureka 注册中心服务名,应为是全部大写#zuul.routes.HELLOSERVICE=/hello-api/**
然后重启服务并访问:http://localhost:8085/helloservice/refact/hello1?name=daifei&accessToken=jjj
请求结果如图:

我们依然获得了预期的响应(棒棒的)。
到这里我们实现了路由的自动创建维护,但是这也带来了一个问题,一些我们不希望被外部访问的服务也会被外部访问到,这时我就需要通过配置参数zuul.ignored-services来设置忽略该服务的路由自动创建动作。我们修改配置文件进行验证:
spring.application.name=api-gatewayserver.port=8085eureka.client.service-url.defaultZone = http://localhost:8070/eureka,http://localhost:8080/eurekazuul.ignored-services=helloservice
重启服务,重新请求:http://localhost:8085/helloservice/refact/hello1?name=daifei&accessToken=jjj
请求结果如图:

返回了404,符合预期,至此我们已经对zuul 的路由配置已经有了初步了解,我们下篇文章来了解如何实现zuul的过滤器。
以上如有不对之处,欢迎指正!





