网关
- 由于微服务“各自为政”的特性,使微服务的使用非常麻烦;
- 通常会雇佣一个“传达室大爷”作为统一入口,这就是网关;
- 网关的主要作用就是请求转发和请求过滤;
Zuul | 介绍
- Zuul 是网关大军中的一员,目前市场的使用规模比较高;
- Zuul 除了实现请求转发和请求过滤之外,一般还作为鉴权和容错使用;
- Zuul 可以无缝衔接 Ribbon 和 Hystrix;
Zuul | serviceId
- Zuul 支持用 spring.application.name 代替 path 的值,比如
http://localhost:8080/film-service/films
和 http://localhost:8080/film-api/films
都可以访问到影片服务;
- 在上产环境中,一般不能这么用,因为直接写 spring.application.name 的话,就暴露了服务的细节;
- ignored-services 可以禁用 serviceId 的使用
Zuul | 请求路由表达式
-
?
-> 匹配任意单个字符;
-
*
-> 匹配任意多个字符;
-
**
-> 匹配任意多个字符,支持多级目录;
Zuul | Filter
Zuul 架构图
Zuul 架构图.png
- ZuulFilter Runner:请求进来之后,由 ZuulFilter Runner 来判断请求该进哪个 Filter;
- Pre routing filter:
- Routing filter:
- Post routing filter:
- Request Context
- Servlet 和 Filtering 是线程非安全的,里面会串数据;
- 使用 Servlet 的 Filter 的时候,很麻烦的一件事是:如果在 Filter 中区分每一次请求之间的不同;
- Request Context 是一个线程安全的对象,每一个请求都会封装一个 Request Context 对象,其中封装了在 Request、Response 以及处理的中间过程中所有的数据;
Zuul 中 Filter 的生命周期
Zuul Filter 生命周期.png
- routing filter(s):真正调服务是 routing filter(s) 在调
- pre filters:在 routing filter(s) 之前就做完了,主要做鉴权、解包、解码、验签;
- post filters:在真实微服务处理完之后,并且返回都有了才会触发,主要做一些数据增强,比如:
- 数据在返回前端的时候,需要签名,post filters 就可以做;
- 返回的数据杂乱无章,post filters 可以对数据做编排,设置 Response 的 Content-Type 等;
- custom filters:用户管理相关的东西
- error filters:用来做容错管理的;
filter | 自定义
- 继承 ZuulFilter 并实现响应的方法;
- 设置 Filter 类型(前、中、后)、级别(执行顺序,从 1 到 2...)和是否启用;
- 开发具体的业务逻辑;
预定义 Filter | PreFilter
Filter 名称 |
Filter 作用 |
ServletDetectionFilter |
检测当前请求是否使用 ZuulServlet 来处理运行,其实就是设置了一个属性 isDispatcherServletRequest |
FromBodyWrapperFilter |
解析表单数据,并对下游请求进行重新编码,其实就是你要是表单数据我就处理,要不是就愿意谁干谁干 |
DebugFilter |
该过滤器会根据配置参数 zuul.debug.request 和请求中的 debug 参数来决定是否执行过滤器中的操作,做一些 Debug 参数的打印 |
PreDecorationFilter |
此过滤器根据提供的 RouteLocator 确定在哪里和如何路由,读配置文件中的内容然后做匹配,如果能匹配,就具体找哪一部分去做 |
预定义 Filter | RoutingFilter
Filter 名称 |
Filter 作用 |
RibbonRoutingFilter |
该过滤器只对请求上下文中,存在 serviceId 参数的请求进行处理,主要是面向服务路由的核心,它是通过使用 Ribbon 和 Hystrix 来向服务示例发起请求,并将服务实例的结果返回 |
SimpleHostRoutingFilter |
该过滤器只对 URL 配置的路由生效,主要是向 routeHost 参数的物理地址发起请求 ,该 Filter 直接使用 httpClient 完成调用,并没有使用 Hystrix 进行封装 |
SendForwardFilter |
该过滤器只对请求上下文中存在的 forward.do 参数进行处理请求,主要用来处理落规则中 forward 本地跳转装配 |
预定义 Filter | RoutingFilter
Filter 名称 |
Filter 作用 |
SendErrorFilter |
该过滤器主要利用上下文中的错误信息,来组成一个 forward 到 api 网关 /error 错误端点的请求,来产生错误响应 |
SendResponseFilter |
该过滤器主要利用上下文的响应信息来组织需要发送回客户端的响应信息 |
Zuul | 版本差异 | Zuul vs Zuul2
- Zuul 使用的是阻塞式线程完成业务调用,一个请求进来,一个线程处理,处理完了返回;
- 好处:开发人员对这个模型非常熟悉;阻塞式的线程是对程序最容易控制的线程;
- 缺点:占用资源非常高;在同样的资源下,没有异步线程的并发量高;
- Zuul2 使用的是异步线程完成业务调用
Zuul 与 Hystrix 整合
Hystrix 超时配置
hystrix:
command:
default:
execution:
timeout:
enabled: true
isolation:
thread:
timeoutInMilliseconds: 10000
Hystrix 降级处理
package com.lixinlei.meetingfilm.apigwzuul.fallbacks;
import com.alibaba.fastjson.JSONObject;
import com.lixinlei.meetingfilm.utils.common.vo.BaseResponseVO;
import com.lixinlei.meetingfilm.utils.exception.CommonServiceException;
import org.springframework.cloud.netflix.zuul.filters.route.FallbackProvider;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.stereotype.Component;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
@Component
public class MyFallback implements FallbackProvider{
/**
* 针对哪一个路由进行降级, return可以写 *
* @return
*/
@Override
public String getRoute() {
return "film-service";
}
/**
* 降级时处理方式
* @param route
* @param cause
* @return
*/
@Override
public ClientHttpResponse fallbackResponse(String route, Throwable cause) {
return new ClientHttpResponse() {
@Override
public HttpStatus getStatusCode() throws IOException {
return HttpStatus.OK;
}
@Override
public int getRawStatusCode() throws IOException {
return 200;
}
@Override
public String getStatusText() throws IOException {
return "OK";
}
@Override
public void close() {
}
/**
* 业务降级处理方式
* @return
* @throws IOException
*/
@Override
public InputStream getBody() throws IOException {
BaseResponseVO responseVO
= BaseResponseVO.serviceException(new CommonServiceException(404, "No Films!~"));
String result = JSONObject.toJSONString(responseVO);
return new ByteArrayInputStream(result.getBytes());
}
@Override
public HttpHeaders getHeaders() {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
return headers;
}
};
}
}
Zuul | Cookie & 特殊头处理
- Zuul 帮我们过滤掉了一些非安全的信息,诸如 cookie、set-Cookie 和 authorization;
- 网关是可以获取到这些信息的,但是不会传给后端服务;
- 如果期望这些信息可以被后端获取,可以通过设置 sensitive-headers 来设置哪些头信息不想透传到后端服务;如果设置空值,则所有头信息都可以透传到后端;
网友评论