SpringCloud中使用Zuul实现路由网关
转载:https://www.cnblogs.com/qdhxhz/p/9594521.html
一、什么是路由网关
网关是系统的唯一对外的入口,介于客户端和服务器端之间的中间层,处理非业务功能 提供路由请求、鉴权、监控、缓存、限流等功能。
它将"1对N"问题转换成了"1对1”问题。
通过服务路由的功能,可以在对外提供服务时,只暴露 网关中配置的调用地址,而调用方就不需要了解后端具体的微服务主机。
二、为什么要使用微服务网关
不同的微服务一般会有不同的网络地址,而客户端可能需要调用多个服务接口才能完成一个业务需求,
若让客户端直接与各个微服务通信,会有以下问题:
- (1)客户端会多次请求不同微服务,增加了客户端复杂性
- (2)存在跨域请求,处理相对复杂
- (3)认证复杂,每个服务都需要独立认证
- (4)难以重构,多个服务可能将会合并成一个或拆分成多个
三、网关的优点
微服务网关介于服务端与客户端的中间层,所有外部服务请求都会先经过微服务网关客户只能跟微服务网关进行交互,
无需调用特定微服务接口,使得开发得到简化
总的理解网关优点
服务网关 = 路由转发 + 过滤器
(1)路由转发:接收一切外界请求,转发到后端的微服务上去。
(2)过滤器:在服务网关中可以完成一系列的横切功能,
例如权限校验、限流以及监控等,这些都可以通过过滤器完成(其实路由转发也是通过过滤器实现的)。
网关: Zuul的使用
1、 创建一个网关的服务(创建一个springboot的jar文件,继承父项目)
2、添加依赖 eureka-client , config-client(使用配置中心), zuul(网关)
<!--添加Eureka-client的依赖 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <!-- zuul网关 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-zuul</artifactId> </dependency>
3、 在启动类上添加注解: @EnableEurekaClient , @EnableZuulProxy
@SpringBootApplication @EnableEurekaClient //作为Eureka的client @EnableZuulProxy //进行网关代理 public class HouseCloudWebZuulApplication { public static void main(String[] args) { SpringApplication.run(HouseCloudWebZuulApplication.class, args); }
4、添加配置, eureka配置, 路由策略
server:
port:
7777
spring: application: name: houseCloud-webZuul #路由的配置: url包含那些字符, 转发到哪一个服务 #hello 标识你服务的名字,这里可以自己定义,一般方便和规范来讲还是跟自己服务的名字一样 zuul: routes: userService: serviceId: house-userService #对应的服务的application.name #服务映射的路径,通过这路径就可以从外部访问你的服务了,目的是为了不爆露你机器的IP,面向服务的路由了,给你选一个可用的出来, #这里zuul是自动依赖hystrix,ribbon的,不是面向单机 path: /userService/**
#第二个服务 houseService: serviceId: house-houseService path: /houseService/**
#第三个服务。。。
前端页面访问:http:localhost:7777/userService/+controller名+参数 (这样就是访问house-userService服务下的数据)
zuul作为过滤的使用案例
Zuul 允许开发者在 API 网关上通过定义过滤器来实现对请求的拦截与过滤,实现的方法非常简单。
Filter 的生命周期有 4 个,分别是 “PRE”、“ROUTING”、“POST” 和“ERROR”
禁用过滤器:(在 application.yml 中配置)
#禁用过滤器 zuul.SendResponseFilter.post.disable=true
自定义过滤器:
我们假设有这样一个场景,因为服务网关应对的是外部的所有请求,为了避免产生安全隐患,
我们需要对请求做一定的限制,比如请求中含有 Token 便让请求继续往下走,
如果请求不带 Token 就直接返回并给出提示。
首先自定义一个 Filter,继承 ZuulFilter 抽象类,在 run() 方法中验证参数是否含有 Token
@Component //交给spring管理 public class TokenFilter extends ZuulFilter{ //过滤器是否有效 // true: 有效, false: 失效 @Override public boolean shouldFilter() { return true; } /** * 过滤器类型 "PRE”、“ROUTING”、“POST” 和“ERROR” * 网关: 路由 * pre: 在路由之前执行 常用 * ROUTING: 正在路由的时候执行 * post: 路由完成之后执行 * error:路由出现错误的时候执行 * */ @Override public String filterType() { return "pre"; } //过滤器执行的顺序, 非负整数, 越小,越先执行 @Override public int filterOrder() { return 0; } /** * 过滤器逻辑代码, 做什么事情 * 访问任意东西,都表示放行 * * 拦截:RequestContext 的 setSendZuulResponse(false) 表示拦截 * http:localhost:7777/sd/ds/dd?token=ssss * request.getParamter() * * request --> ServletRequestAttributes得到 * ServletRequestAttributes --> RequestContext(请求上下文) * RequestContext --> RequestContext.getCurrentContext() 获取当前请求上下文 * */ @Override public Object run() throws ZuulException { RequestContext requestContext = RequestContext.getCurrentContext(); HttpServletRequest request = requestContext.getRequest();//requestContext.getResponse() String token = request.getParameter("token"); if(request.getRequestURI().indexOf("login") > 0) { return null; //返回空表示通过 } if(null == token || token.isEmpty()) {//没有token requestContext.setSendZuulResponse(false); //requestContext.getResponse().getWriter().print("权限不足,禁止访问"); requestContext.getResponse().setContentType("text/html;charset=utf-8"); requestContext.setResponseBody("权限不足,禁止访问"); requestContext.setResponseStatusCode(401); //404 资源不存在 405: 提交方式不支持, 400参数绑定错误 401/403 权限不足 return null; } return null; } }
url请求参数如果含有token表示通过执行,如果是login页面,或者设置注册页面是否满足条件通过
否则返回权限不足
我们可以根据自己的需要在服务网关上定义一些与业务无关的通用逻辑实现对请求的过滤和拦截,比如:签名校验、权限校验、请求限流等功能