本篇文章基于:
01) 玩转 SpringCloud 一.服务的注册与发现 (Eureka)
02) 玩转 SpringCloud 二.服务消费者 (1)ribbon+restTemplate
03) 玩转 SpringCloud 二.服务消费者 (2)feign
04) 转 SpringCloud 三.断路器 (Hystrix)RestTemplate+Ribbon 和 Feign 两种方式
四.路由网关 (zuul)
在微服务架构中, 需要几个基础的服务治理组件, 包括服务注册与发现, 服务消费, 负载均衡, 断路器, 智能路由, 配置管理等, 由这几个基础组件相互协作, 共同组建了一个简单的微服务系统.
在 Spring Cloud 微服务系统中, 一种常见的负载均衡方式是, 客户端的请求首先经过负载均衡 (zuul,Ngnix), 再到达服务网关 (zuul 集群), 然后再到具体的服., 服务统一注册到高可用的服务注册中心集群, 服务的所有的配置文件由配置服务管理, 配置服务的配置文件放在 git 仓库, 方便开发人员随时改配置.
一, Zuul 简介
Zuul 的主要功能是路由转发和过滤器. 路由功能是微服务的一部分, 比如 / api/user 转发到到 user 服务,/api/shop 转发到到 shop 服务. zuul 默认和 Ribbon 结合实现了负载均衡的功能.
zuul 有以下功能:
- . Authentication
- . Insights
- . Stress Testing
- . Canary Testing
- . Dynamic Routing
- . Service Migration
- . Load Shedding
- . Security
- . Static Response handling
- . Active/Active traffic management
二, 配置路由
项目架构:
在原有的工程上, 创建一个新的工程. demo5
依赖主工程以及所需 jar 包:
- <parent>
- <groupId>com.fsdm</groupId>
- <artifactId>SpringCloud_test1</artifactId>
- <version>1.0-SNAPSHOT</version>
- </parent>
- <dependencies>
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-web</artifactId>
- </dependency>
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
- </dependency>
- </dependencies>
在其入口 applicaton 类加上注解 @EnableZuulProxy, 开启 zuul 的功能:
- @SpringBootApplication
- @EnableZuulProxy
- @EnableEurekaClient
- @EnableDiscoveryClient
- public class Demo5Application {
- public static void main(String[] args) {
- SpringApplication.run(Demo5Application.class, args);
- }
- }
注解解析:
@EnableZuulProxy
如果使用注解 @EnableZuulProxy, 那么除上述过滤器之外, Spring Cloud 还会增加以下过滤器:
1,pre 类型过滤器
PreDecorationFilter: 该过滤器根据提供的 RouteLocator 确定路由到的地址, 以及怎样去路由. 该路由器也可为后端请求设置各种代理相关的 header.
2,route 类型过滤器
(1) RibbonRoutingFilter: 该过滤器使用 Ribbon,Hystrix 和可插拔的 HTTP 客户端发送请求. serviceId 在 RequestContext.getCurrentContext().get("serviceId") 中. 该过滤器可使用不同的 HTTP 客户端, 例如
Apache HttpClient: 默认的 HTTP 客户端
SquareupOkHttpClient v3: 如需使用该客户端, 需保证 com.squareup.okhttp3 的依赖在 classpath 中, 并设置 ribbon.okhttp.enabled = true.
Netflix Ribbon HTTP client: 设置 ribbon.restclient.enabled = true 即可启用该 HTTP 客户端. 需要注意的是, 该客户端有一定限制, 例如不支持 PATCH 方法, 另外, 它有内置的重试机制.
(2) SimpleHostRoutingFilter: 该过滤器通过 Apache HttpClient 向指定的 URL 发送请求. URL 在 RequestContext.getRouteHost() 中.
yml 配置:
- eureka:
- client:
- serviceUrl:
- defaultZone: http://localhost:8761/eureka/
- server:
- port: 8766
- spring:
- application:
- name: service-zuul
- zuul:
- routes:
- api-a:
- path: /api-a/**
- serviceId: service-ribbon
- api-b:
- path: /api-b/**
- serviceId: service-feign
- 首先指定服务注册中心的地址为 http://localhost:8761/eureka/ , 服务的端口为 8766, 服务名为 service-zuul; 以 / api-a/ 开头的请求都转发给 service-ribbon 服务; 以 / api-b / 开头的请求都转发给 service-feign 服务;
- 把五个项目都跑起来:
- 打开浏览器分别访问:
- http://localhost:8766/api-a/hi?name=fsdm http://localhost:8769/api-a/hi?name=forezp ;
- http://localhost:876/api-b/hi?name=fsdm http://localhost:8769/api-a/hi?name=forezp ;
- 浏览器显示:
- 这说明 zuul 起到了路由的作用
- 三, 服务过滤
- 项目架构:
- zuul 不仅只是路由, 并且还能过滤, 做一些安全验证. 继续改造工程;
- 添加过滤器类:
- @Component
- public class MyFilter extends ZuulFilter {
- /**
- * filterType: 返回一个字符串代表过滤器的类型, 在 zuul 中定义了四种不同生命周期的过滤器类型, 具体如下:
- * pre: 路由之前
- * routing: 路由之时
- * post: 路由之后
- * error: 发送错误调用
- */
- @Override
- public String filterType() {
- return "pre";
- }
- // 过滤的顺序
- @Override
- public int filterOrder() {
- return 0;
- }
- // 这里可以写逻辑判断, 是否要过滤, 本文 true, 永远过滤.
- @Override
- public boolean shouldFilter() {
- return true;
- }
- // 过滤器的具体逻辑. 可用很复杂, 包括查 sql,nosql 去判断该请求到底有没有权限访问.
- @Override
- public Object run() throws ZuulException {
- System.out.println("==============================================================");
- RequestContext ctx = RequestContext.getCurrentContext();
- HttpServletRequest request = ctx.getRequest();
- System.out.println(String.format("%s>>> %s", request.getMethod(), request.getRequestURL().toString()));
- Object accessToken = request.getParameter("token");
- if(accessToken == null) {
- System.out.println("token is empty");
- ctx.setSendZuulResponse(false);
- ctx.setResponseStatusCode(401);
- try {
- ctx.getResponse().getWriter().write("token is empty");
- }catch (Exception e){}
- return null;
- }
- System.out.println("ok");
- return null;
- }
- }
访问: http://localhost:8766/api-a/hi?name=fsdm http://localhost:8769/api-a/hi?name=forezp ; 网页显示:
访问 http://localhost:8766/api-a/hi?name=fsdm&token=22 页面显示:
这里是一个非常简单的模拟验证, 通过是否又 token 值来决定是否有权限访问
未完, 待续...
来源: https://www.cnblogs.com/lsy131479/p/9635075.html