【Spring Cloud 系列 六】Zuul 构建微服务网关

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


当使用微服务架构时,我们会将单体应用拆分成很多小的服务,每个服务一般都会有不同的网络地址,而客户端可能需要调用多个服务接口才能完成一个业务需求,这样客户端就会直接与各个服务进行通信,造成以下可能出现的问题:

  • 客户端多次请求不同的微服务,增加了客户端的复杂性
  • 存在跨域请求,在一定场景下处理相对复杂
  • 认证复杂,每个服务都需要独立认证
  • 难以重构,随着项目的迭代,可能需要重新划分微服务,那么客户端如果直接和服务进行通信,那么将会很难进行重构

以上问题都可以通过加入网关来解决,网关是介于客户端和微服务端之间的中间层,所有的外部请求都需要先经过微服务网关,然后由网关在进行进一步的处理。封装了应用程序的内部结构,客户端只需要与网关打交道。


二 Zuul 简介


Zuul 是 Netflix 开源的微服务网关,可以和 Eureka、Ribbon、Hystrix 等组件配合使用。Zuul 的核心是提供了一些列的过滤器,完成下列功能:

  • 身份认证与安全:识别每个资源的验证要求,并拒绝那些不符合要求的请求
  • 审查与监控:在边缘位置追踪有意义的数据和统计结果
  • 动态路由
  • 压力测试:为每一种负载类型分配相应容量,并启用超出限定值的请求
  • 静态响应处理:在边缘位置直接建立部分响应,从而避免其转发到内部集群

Spring Cloud 对 Zuul 进行了整合与增强,Zuul 目前使用的默认HTTP 客户端是 Apache HTTP client,也可以设置使用 RestClient 或者 okhttp3.OKHttpClient,只需要设置对应的配置ribbon.restclient.enabled=trueribbon.okhttp.enabled=true

三 编写 Zuul 微服务网关


1 创建一个新项目(microservice-gateway-zuul),并添加相关依赖
 compile group: 'org.springframework.cloud', name: 'spring-cloud-starter-netflix-zuul', version:'1.4.0.RELEASE'
    compile group: 'org.springframework.cloud', name: 'spring-cloud-starter-netflix-eureka-client', version:'1.4.0.RELEASE'
2 在启动类上添加注解@EnableZuulProxy,声明一个代理,该代理同时还整合了 Ribbon 和 Hystrix
@SpringBootApplication
@EnableZuulProxy
public class ZuulApplication {
  public static void main(String[] args) {
    SpringApplication.run(ZuulApplication.class, args);
  }
}

3 编写配置文件application.yml
server:
  port: 8040
spring:
  application:
    name: microservice-gateway-zuul
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/
  instance:
    prefer-ip-address: true
4 启动相关的服务
  • microservice-discovery-eureka
  • mircroservice-provider-user
  • microservice-consumer-movie-ribbon
  • microservice-gateway-zuul

当访问 http://localhost:8040/microservice-consumer-movie/user/1 时,请求会被转发到 mocroservice-consumer-movie-ribbon服务中的 /user/1 接口。

四 路由配置详解


在上个demo中我们对不同的service的 application name 进行了代理,我们还可以使用 Zull 代理部分服务,或者对 URL 进行更加准确的控制

自定义指定微服务的访问路径

配置 zuul.routes.「指定微服务的 serviceId」= 指定路径,例如

zuul:
  routes:
    microservice-provider-user: /user/**
通配符 含义 举例 解释
? 匹配任意单个字符 /feign-consumer/? 匹配/feign-consumer/a,/feign-consumer/b,/feign-consumer/c等
* 匹配任意数量的字符 /feign-consumer/* 匹配/feign-consumer/aaa,feign-consumer/bbb,/feign-consumer/ccc等,无法匹配/feign-consumer/a/b/c
** 匹配任意数量的字符 /feign-consumer/* 匹配/feign-consumer/aaa,feign-consumer/bbb,/feign-consumer/ccc等,也可以匹配/feign-consumer/a/b/c
忽略指定微服务
zuul:
  ignored-services: microservice-provider-user,microservice-consumer-movie // 多个服务使用 , 分割
忽略所有服务,只路由指定的服务
zuul:
  ignored-services: '*'   # 使用'*'可忽略所有微服务
  routes:
    microservice-provider-user: /user/**
同时指定服务的 serviceId 和 对应路径
zuul:
  routes:
    user-route:                   # 该配置方式中,user-route只是给路由一个名称,可以任意起名。
      service-id: microservice-provider-user
      path: /user/**              # service-id对应的路径
同时指定 path 和 URL
zuul:
  routes:
    user-route:                   # 该配置方式中,user-route只是给路由一个名称,可以任意起名。
      url: http://localhost:8000/ # 指定的url
      path: /user/**              # url对应的路径。

这种配置方式的路由 HystrixRibbon 都不会工作

同时指定 URL 和 path,并且 HystrixRibbon 可以正常工作
zuul:
  routes:
    user-route:
      path: /user/**
      service-id: microservice-provider-user
ribbon:
  eureka:
    enabled: false    # 禁用掉ribbon的eureka使用。详见:http://cloud.spring.io/spring-cloud-static/Camden.SR3/#_example_disable_eureka_use_in_ribbon
microservice-provider-user:
  ribbon:
    listOfServers: localhost:8000,localhost:8001
路由前缀
zuul:
  prefix: /api
  strip-prefix: false
  routes:
    microservice-provider-user: /user/**

当访问 Zuul 的 /api/mocroservice-provide-user/1 时会被转发到 microservice-provider-user/api/1

忽略某些路径
zuul:
  ignoredPatterns: /**/admin/**   # 忽略所有包括/admin/的路径
  routes:
    microservice-provider-user: /user/**
五 Zuul 的安全与 Header
敏感 Header 的设置

不同服务之间通信时会共享 Header,可以对敏感的 Header 进行设置,避免外泄

zuul:
  routes:
    user-route:
      path: /user/**
      service-id: microservice-provider-user
      sensitive-headers: Cookie, Set-Cookie ... 
忽略 Header
zuul:
  ignored-headers: Header 1, header 2

默认情况下,zuul.ignored-headers 是空值,但如果项目中存在 Spring security的依赖,那么 zuul.ignored-headers 就会存在一些header,如果我们需要使用下游服务中的 header 时,需要将 zuul.ingoredSecurity-Headers设置为 false

六 Zuul 的容错与回退


在 Spring Cloud 中,Zuul 已经默认整合了 hystrix。想要为 Zuul 添加回退,需要实现 ZuulFallbackProvider 接口,在实现类中,指定为哪个服务提供回退,并提供一个 ClientResponse 作为回退响应,例如:

@Component
public class MyFallbackProvider implements FallbackProvider {
  @Override
  public String getRoute() {
    // 表明是为哪个微服务提供回退,*表示为所有微服务提供回退
    return "*";
  }

  @Override
  public ClientHttpResponse fallbackResponse(Throwable cause) {
    if (cause instanceof HystrixTimeoutException) {
      return response(HttpStatus.GATEWAY_TIMEOUT);
    } else {
      return this.fallbackResponse();
    }
  }

  @Override
  public ClientHttpResponse fallbackResponse() {
    return this.response(HttpStatus.INTERNAL_SERVER_ERROR);
  }

  private ClientHttpResponse response(final HttpStatus status) {
    return new ClientHttpResponse() {
      @Override
      public HttpStatus getStatusCode() throws IOException {
        return status;
      }

      @Override
      public int getRawStatusCode() throws IOException {
        return status.value();
      }

      @Override
      public String getStatusText() throws IOException {
        return status.getReasonPhrase();
      }

      @Override
      public void close() {
      }

      @Override
      public InputStream getBody() throws IOException {
        return new ByteArrayInputStream("服务不可用,请稍后再试。".getBytes());
      }

      @Override
      public HttpHeaders getHeaders() {
        // headers设定
        HttpHeaders headers = new HttpHeaders();
        MediaType mt = new MediaType("application", "json", Charset.forName("UTF-8"));
        headers.setContentType(mt);
        return headers;
      }
    };
  }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,193评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,306评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,130评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,110评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,118评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,085评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,007评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,844评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,283评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,508评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,667评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,395评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,985评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,630评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,797评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,653评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,553评论 2 352

推荐阅读更多精彩内容