为什么需要 zuul?
Zuul Ribbon 以及 Eureka 相结合 可以实现智能路由和负载均衡的功能
网关将所有服务的 API 接口统一聚合 并统一对外暴露
网关服务可以做用户身份认证和权限认证 防止非法请求操作 API 接口 对服务器起到保护作用.
Zuul 过滤器的类型
PRE 过滤器: 请求路由到具体的服务之前执行 可以做安全验证, 例如身份验证, 参数验证等.
ROUTING 过滤器: 将请求路由到具体的微服务实例
POST 过滤器: 请求己被路由到微服务后执行 用作收集统计信息, 指标, 以及将响应传输到客户端
ERROR 过滤器 : 在其他过滤器发生错误时执行
过滤器之间不能直接相互通信 而是通过 RequestContext 对象来共享数据, 每个请求都会创建一个 RequestContext 对象
执行流程
案例
创建新工程 (继承父工程)
导入依赖
- <dependencies>
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-starter-eureka-server</artifactId>
- </dependency>
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-starter-zuul</artifactId>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-web</artifactId>
- </dependency>
- </dependencies>
启动类
- @SpringBootApplication
- // 开启 Zuul 功能
- @EnableZuulProxy
- @EnableEurekaClient
- public class ZuulApp
- {
- public static void main( String[] args )
- {
- SpringApplication.run(ZuulApp.class);
- }
- }
配置文件
- server:
- port: 8009
- eureka:
- instance:
- hostname: service-zuul
- client:
- service-url:
- defaultZone:
- http://eureka01:8001/eureka/
- register-with-eureka: true
- spring:
- application:
- name: service-zuul
- zuul:
- routes:
- hiapi:
- # 将以 / hiapi 开头的路由到 eureka-client 服务
- path: /hiapi/**
- serviceId: eureka-client
- ribbonapi:
- path: /ribbonapi/**
- serviceId: ribbon-client
- feignapi:
- path: /feignapi/**
- serviceId: feign-client
修改 host 文件
127.0.0.1 eureka01 eureka02 eureka-client ribbon-client feign-client
启动服务
打开浏览器输入
http://localhost:8009/hiapi/hi/aa
刷新
Zuul 在路由转发做了负载均衡 如果不需要用 Ribbon 做负载均衡 可以指定服务实例的 Url 一旦指定了 Uri Zuul 就不能做负载均衡了 而是直接访问指定的 Uri 在实际的开发中这种做法是不可取的
- zuul:
- routes:
- hiapi:
- path: /hiapi/**
- # serviceId: eureka-client
- url: http://eureka-client:8006
- ribbonapi:
- path: /ribbonapi/**
- serviceId: ribbon-client
- feignapi:
- path: /feignapi/**
- serviceId: feign-client
重启服务后 继续刷新 可以看到不负载了
在 Zuul 上配置 API 接口的版本号
- zuul:
- routes:
- hiapi:
- path: /hiapi/**
- # serviceId: eureka-client
- url: http://eureka-client:8006
- ribbonapi:
- path: /ribbonapi/**
- serviceId: ribbon-client
- feignapi:
- path: /feignapi/**
- serviceId: feign-client
- # 版本号前缀
- prefix: /v3
访问要加 V3 前缀
Zuul 上配置熔断器
实现 ZuulFallbackProvider 接口
- @Component
- public class ZuulError implements ZuulFallbackProvider {
- @Override
- public String getRoute() {
- // 如果要将所有服务加熔断器 加 *
- // returen "*"
- return "eureka-client";
- }
- @Override
- public ClientHttpResponse fallbackResponse() {
- 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() {
- }
- @Override
- public InputStream getBody() throws IOException {
- return new ByteArrayInputStream("eureka-client error".getBytes());
- }
- @Override
- public HttpHeaders getHeaders() {
- HttpHeaders httpHeaders = new HttpHeaders();
- httpHeaders.setContentType(MediaType.APPLICATION_JSON);
- return httpHeaders;
- }
- };
- }
- }
配置文件
- zuul:
- routes:
- hiapi:
- path: /hiapi/**
- serviceId: eureka-client
- ribbonapi:
- path: /ribbonapi/**
- serviceId: ribbon-client
- feignapi:
- path: /feignapi/**
- serviceId: feign-client
重启服务 关闭 eureka_client 服务
打开浏览器访问
zuul 过滤器
打开工程
在 controller 层 新增
- @RequestMapping("/test")
- public String test(@RequestParam("name") String name){
- return "有 name 参数";
- }
打开工程
新建 ZuulFilterDemo 类 实现 zuulFilter 接口
- @Component
- public class ZuulFilterDemo extends ZuulFilter {
- @Override
- public String filterType() {
- //PRE 过滤器: 请求路由到具体的服务之前执行 可以做安全验证, 例如身份验证, 参数验证等.
- // ROUTING 过滤器: 将请求路由到具体的微服务实例
- // POST 过滤器: 请求己被路由到微服务后执行 用作收集统计信息, 指标, 以及将响应传输到客户端
- // ERROR 过滤器 : 在其他过滤器发生错误时执行
- return "pre";
- }
- @Override
- public int filterOrder() {
- // 过滤顺序 值越小 越早过滤
- return 0;
- }
- @Override
- public boolean shouldFilter() {
- // true 执行 run false 不执行
- return true;
- }
- @Override
- public Object run() {
- // 判断是否有 name 参数
- RequestContext currentContext = RequestContext.getCurrentContext();
- HttpServletRequest request = currentContext.getRequest();
- HttpServletResponse response = currentContext.getResponse();
- String name = request.getParameter("name");
- if(StringUtils.isEmpty(name)){
- try {
- response.setCharacterEncoding("utf-8");
- response.getWriter().write("error");
- currentContext . setSendZuulResponse(false) ;
- currentContext . setResponseStatusCode(401) ;
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- return null;
- }
- }
启动服务器
访问 http://localhost:8009/hiapi/test 此时没有携带参数 返回 error
携带 name 参数后
来源: http://www.bubuko.com/infodetail-3459524.html