上一篇已经讲了微服务组件中的 分布式配置中心,本章讲述 由JAVA编写的服务路由网关Zuul

- Zuul

路由是微服务体系结构的一个组成部分。例如 / 可以映射到您的Web应用程序,/api/users映射到用户服务,/api/shop映射到商店服务。Zuul是Netflix的基于JVM的开发的路由和服务器端负载均衡器。

为什么需要服务网关?

如果没有服务网关,多个服务提供给前端调用地址管理错综复杂,增加了客户端的复杂性,认证也相对麻烦,每个服务都需要编写相同的认证….

Zuul架构图

画图工具:https://www.processon.com/

Zuul 可以做什么?

  • 身份认证
  • 审查与监控
  • 压力测试
  • 金丝雀测试
  • 动态路由
  • 服务迁移
  • 负载分配
  • 安全
  • 静态响应处理
  • 主动/主动流量管理

Zuul的规则引擎允许基本上写任何JVM语言的规则和过滤器,内置Java和Groovy的支持。

注意:配置属性 zuul.max.host.connections 已被取代的两个新的属性,zuul.host.maxTotalConnections并且zuul.host.maxPerRouteConnections 它的缺省值分别200和20。

注意:所有路线的默认Hystrix隔离模式(ExecutionIsolationStrategy)为SEMAPHOREzuul.ribbonIsolationStrategy 如果此隔离模式是首选,可以更改为THREAD

官方文档:http://cloud.spring.io/spring-cloud-static/Dalston.SR2/#_router_and_filter_zuul

- 准备工作

1.启动Consul
2.创建 battcn-gateway-service 和 battcn-hello-service

- battcn-gateway-service

1.在项目 pom.xml 中添加 ZUUL 依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zuul</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

2.App.java中开启 zuul 代理

1
2
3
4
5
6
7
8
9
@EnableZuulProxy
@EnableDiscoveryClient
@SpringBootApplication
public class ZuulApplication { public static void main(String[] args) {
SpringApplication.run(ZuulApplication.class, args);
}
}

3.zuul.routes.routesName.ZuulProperties.ZuulRoute 配置的方式,详细可以参考源码org.springframework.cloud.netflix.zuul.filters.ZuulProperties

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
server:
port: 9000 zuul:
routes:
hello-service: #自定义的 路由名称
path: /api-hello/** #路由路径
serviceId: battcn-hello-service #VIP 模式中的 serviceId spring:
application:
name: battcn-gateway-service
cloud:
consul:
host: localhost
port: 8500
enabled: true
discovery:
enabled: true
prefer-ip-address: true

- battcn-hello-service

hello-service 只需要以下依赖,能注册到consul中就行(单纯的一个服务)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
1
2
3
4
5
6
7
8
@EnableDiscoveryClient
@SpringBootApplication
public class HelloApplication { public static void main(String[] args) {
SpringApplication.run(HelloApplication.class, args);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
server:
port: 9001 spring:
application:
name: battcn-hello-service
cloud:
consul:
host: localhost
port: 8500
enabled: true
discovery:
enabled: true
prefer-ip-address: true

- 测试一把

访问:http://localhost:9000/api-hello/hello 从地址中可以看出我们访问的是 battcn-gateway-service,且满足 zuul.routes.routesName.path 规则,因此实际请求地址是http://localhost:9001/hello

1
hello:battcn-hello-service		#表示请求成功

- 自定义过滤器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import org.springframework.stereotype.Component; import javax.servlet.http.HttpServletRequest; /**
* 网关认证过滤器(Demo演示,实际根据自身业务考虑实现)
* @author Levin
* @date 2017-08-14.
*/
@Component
public class GatewayZuulFilter extends ZuulFilter { /**
* per:路由之前,如实现认证、记录调试信息等
* routing:路由时
* post:路由后,比如添加HTTP Header
* error:发生错误时调用
*/
@Override
public String filterType() {
return "pre";
} /**
* 过滤器顺序,类似@Filter中的order
*/
@Override
public int filterOrder() {
return 0;
} /**
* 这里可以写逻辑判断,是否要过滤,本文true,永远过滤。
*/
@Override
public boolean shouldFilter() {
return true;
} /**
* 过滤器的具体逻辑。可用很复杂,包括查sql,nosql去判断该请求到底有没有权限访问。
*/
@Override
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
String token = request.getParameter("token");
if(token == null) {
ctx.setSendZuulResponse(false);
ctx.setResponseStatusCode(404);
ctx.setResponseBody("token cannot be empty");
}
return null;
}
}

实际开发中token应该从请求头中获取,该处只是为了方便演示效果

访问:http://localhost:9000/api-hello/hello?token=1

1
hello:battcn-hello-service

访问:http://localhost:9000/api-hello/hello

1
token cannot be empty

- 路由映射流程

图不是很严谨,凑合着看看吧…

HanderMapping

初次启动项目我们可以看到

1
2
3
4
2017-08-14 17:19:06.090  INFO 11544 --- [nio-9000-exec-1] o.s.c.n.zuul.web.ZuulHandlerMapping      : Mapped URL path [/api-hello/**] onto handler of type [class org.springframework.cloud.netflix.zuul.web.ZuulController]
2017-08-14 17:19:06.090 INFO 11544 --- [nio-9000-exec-1] o.s.c.n.zuul.web.ZuulHandlerMapping : Mapped URL path [/battcn-gateway-service/**] onto handler of type [class org.springframework.cloud.netflix.zuul.web.ZuulController]
2017-08-14 17:19:06.090 INFO 11544 --- [nio-9000-exec-1] o.s.c.n.zuul.web.ZuulHandlerMapping : Mapped URL path [/battcn-hello-service/**] onto handler of type [class org.springframework.cloud.netflix.zuul.web.ZuulController]
2017-08-14 17:19:06.090 INFO 11544 --- [nio-9000-exec-1] o.s.c.n.zuul.web.ZuulHandlerMapping : Mapped URL path [/consul/**] onto handler of type [class org.springframework.cloud.netflix.zuul.web.ZuulController]

有兴趣的还可以阅读下 com.netflix.loadbalancer.LoadBalancerContext,通过它可以发现每次请求的IP和端口,需要在application.yml 中配置

1
2
3
logging:
level:
com.netflix: DEBUG
1
2
3
4
5
6
2017-08-14 17:32:16.793 DEBUG 14316 --- [nio-9000-exec-7] c.n.zuul.http.HttpServletRequestWrapper  : Path = null
2017-08-14 17:32:16.793 DEBUG 14316 --- [nio-9000-exec-7] c.n.zuul.http.HttpServletRequestWrapper : Transfer-Encoding = null
2017-08-14 17:32:16.793 DEBUG 14316 --- [nio-9000-exec-7] c.n.zuul.http.HttpServletRequestWrapper : Content-Encoding = null
2017-08-14 17:32:16.793 DEBUG 14316 --- [nio-9000-exec-7] c.n.zuul.http.HttpServletRequestWrapper : Content-Length header = -1
2017-08-14 17:32:16.793 DEBUG 14316 --- [nio-9000-exec-7] c.n.loadbalancer.ZoneAwareLoadBalancer : Zone aware logic disabled or there is only one zone
2017-08-14 17:32:16.793 DEBUG 14316 --- [nio-9000-exec-7] c.n.loadbalancer.LoadBalancerContext : battcn-hello-service using LB returned Server: 192.168.31.221:9001 for request /hello

- Zuul Fallback

定义GatewayZuulFallback 实现 ZuulFallbackProvider 接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
/**
* @author Levin
* @date 2017-08-14.
*/
@Component
public class GatewayZuulFallback implements ZuulFallbackProvider {
@Override
public String getRoute() {
return "battcn-hello-service";//指定回退的服务名
} @Override
public ClientHttpResponse fallbackResponse() {
return new ClientHttpResponse() {
@Override
public HttpStatus getStatusCode() throws IOException {
return HttpStatus.INTERNAL_SERVER_ERROR; //INTERNAL_SERVER_ERROR(500, "Internal Server Error")
} @Override
public int getRawStatusCode() throws IOException {
return this.getStatusCode().value();// 500
} @Override
public String getStatusText() throws IOException {
return this.getStatusCode().getReasonPhrase();// Internal Server Error
} @Override
public void close() {} @Override
public InputStream getBody() throws IOException {
return new ByteArrayInputStream(getStatusText().getBytes());//也可以随意写自己想返回的内容
} @Override
public HttpHeaders getHeaders() {
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setContentType(MediaType.APPLICATION_JSON_UTF8);
return httpHeaders;
}
};
}
}

步骤:停掉 battcn-hello-service 启动 battcn-gateway-service

访问:http://localhost:9000/api-hello/hello?token=1

显示:

1
Internal Server Error  # 代表Fallback成功

- 路由配置详解

zuul 相关的官方文档还是比较其全了,本文也是参考官方然后简单讲述应用场景,具体开发请结合自身业务扩展….

1.自定义指定微服务路径,以下两种配置方式结果相同

1
2
3
4
5
6
7
8
9
zuul:
routes:
battcn-hello-service: /api-hello/**
#两种配置方式结果相同
zuul:
routes:
hello-service:
path: /api-hello/**
serviceId: battcn-hello-service

2.忽略指定服务,多个服务逗号分隔,Set<String> ignoredServices 这样一来zuul就会忽略service1和service2,只会代理其它的

1
2
zuul:
ignored-services: battcn-hello-service1,battcn-hello-service2

3.指定Path和Url

1
2
3
4
5
zuul:
routes:
hello-service:
path: /api-hello/** #路由路径
url: http://localhost:9001/ #指定URL地址

4.使用Zuul但不指定Url(该方式在Eureka有效,Consul还未找到解决方法…)

1
2
3
4
5
6
7
8
9
zuul:
routes:
battcn-hello-service: /api-hello/**
ribbon:
eureka:
enabled: false #为Ribbon禁用 eureka,不会破坏Zuul的Hystrix和Ribbon特性
battcn-hello-service:
ribbon:
listOfServers: localhost:9001,localhost:9002

路由网关(Zuul)的更多相关文章

  1. 玩转SpringCloud(F版本) 四.路由网关(zuul)

    本篇文章基于: 01)玩转SpringCloud 一.服务的注册与发现(Eureka) 02) 玩转SpringCloud 二.服务消费者(1)ribbon+restTemplate 03) 玩转Sp ...

  2. 白话SpringCloud | 第十一章:路由网关(Zuul):利用swagger2聚合API文档

    前言 通过之前的两篇文章,可以简单的搭建一个路由网关了.而我们知道,现在都奉行前后端分离开发,前后端开发的沟通成本就增加了,所以一般上我们都是通过swagger进行api文档生成的.现在由于使用了统一 ...

  3. 白话SpringCloud | 第十章:路由网关(Zuul)进阶:过滤器、异常处理

    前言 简单介绍了关于Zuul的一些简单使用以及一些路由规则的简单说明.而对于一个统一网关而言,需要处理各种各类的请求,对不同的url进行拦截,或者对调用服务的异常进行二次处理等等.今天,我们就来了解下 ...

  4. SpringCloud学习系列之六 ----- 路由网关Zuul基础使用教程

    前言 在上篇中介绍了SpringCloud Config的完美使用版本,本篇则介绍基于SpringCloud(基于SpringBoot2.x,.SpringCloud Finchley版)中的路由网关 ...

  5. 白话SpringCloud | 第九章:路由网关(Zuul)的使用

    前言 介绍完分布式配置中心,结合前面的文章.我们已经有了一个微服务的框架了,可以对外提供api接口服务了.但现在试想一下,在微服务框架中,每个对外服务都是独立部署的,对外的api或者服务地址都不是不尽 ...

  6. springCloud之路API路由网关Zuul

    1.简介 简单的理解就是,相当于在所有服务的调用前加了一层防火墙, 主要就是对外提供服务接口的时候,起到了请求的路由和过滤作用,也因此能够隐藏内部服务的接口细节,提高系统的安全性: 官方文档:http ...

  7. 微服务之路由网关—zuul

    Zuul 简介Zuul 是 Netflix 公司开发的一个开源 APIGateway,其本质上是一个 WebServlet 应用.Zuul 的核心是一系列的 Filter. 为什么要使用 Zuul微服 ...

  8. SpringCloud教程 | 第五篇: 路由网关(zuul)(Finchley版本)

    在微服务架构中,需要几个基础的服务治理组件,包括服务注册与发现.服务消费.负载均衡.断路器.智能路由.配置管理等,由这几个基础组件相互协作,共同组建了一个简单的微服务系统.一个简答的微服务系统如下图: ...

  9. spring cloud 路由网关zuul基本使用

    在微服务架构中,需要几个关键的组件,服务注册与发现.服务消费.负载均衡.断路器.智能路由.配置管理等,由这几个组件可以组建一个简单的微服务架构.客户端的请求首先经过负载均衡(zuul.Ngnix),再 ...

  10. 史上最简单的SpringCloud教程 | 第五篇: 路由网关(zuul)

    在微服务架构中,需要几个基础的服务治理组件,包括服务注册与发现.服务消费.负载均衡.断路器.智能路由.配置管理等,由这几个基础组件相互协作,共同组建了一个简单的微服务系统.一个简答的微服务系统如下图: ...

随机推荐

  1. Java实现 LeetCode 23 合并K个排序链表

    23. 合并K个排序链表 合并 k 个排序链表,返回合并后的排序链表.请分析和描述算法的复杂度. 示例: 输入: [ 1->4->5, 1->3->4, 2->6 ] 输 ...

  2. java实现三角螺旋阵

    方阵的主对角线之上称为"上三角". 请你设计一个用于填充n阶方阵的上三角区域的程序.填充的规则是:使用1,2,3-.的自然数列,从左上角开始,按照顺时针方向螺旋填充. 例如:当n= ...

  3. CDN百科第三讲 | 如果用了云服务器,还需要做CDN加速吗?

    在全站上云的背景下,云计算已经不仅仅是大型互联网公司的独享概念,正在被更多的传统企业.中小企业甚至个人站长所采用.在众多云计算服务中,最常见两个产品就是云服务器和CDN,今天的CDN百科第三讲,就给大 ...

  4. Elasticsearch 别管原理,先run起来

    少点代码,多点头发 本文已经收录至我的GitHub,欢迎大家踊跃star 和 issues. https://github.com/midou-tech/articles 看文章有两点需要注意: 本公 ...

  5. [原创][开源] SunnyUI.Net 安装

    SunnyUI.Net, 基于 C# .Net WinForm 开源控件库.工具类库.扩展类库.多页面开发框架 Blog: https://www.cnblogs.com/yhuse Gitee: h ...

  6. Ubuntu安装qwt步骤

    1.svn获取代码 svn checkout https://svn.code.sf.net/p/qwt/code/trunk/qwt 2.生产makefile qmake 3.编译(确保已经安装了q ...

  7. Android 图片裁剪踩坑

      今天做图库图片的裁剪遇到了不少坑,今天记录一下,以下坑位供各位看官参考: 如果有不对之处,欢迎各位看官留言评论! 图片裁剪踩坑锦囊: 问题一:相册裁剪权限问题 解:这个简单,对于Android6. ...

  8. 不需重新编译php,安装postgresql扩展(pgsql和pdo_pgsql)

    为了不重新编译php,使用phpize工具进行追加. 1.下载phpX安装包 访问php官方下载页,找到自己对应的php版本:https://secure.php.net/downloads.php ...

  9. 如何修改centOS7的GUI图形界面

    在安装Gnome包之前,需要检查一下安装源(yum)是否正常,因为需要在yum命令来安装gnome包. 第一步:先检查yum 是否安装了,以及网络是否有网络.如果这两者都没有,先解决网络,在解决yum ...

  10. Python 图像处理 OpenCV (9):图像处理形态学开运算、闭运算以及梯度运算

    前文传送门: 「Python 图像处理 OpenCV (1):入门」 「Python 图像处理 OpenCV (2):像素处理与 Numpy 操作以及 Matplotlib 显示图像」 「Python ...