SpringCloud--08、网关Zuul

版权声明:转载 请注明 原始链接 https://blog.csdn.net/sswqzx/article/details/84782107

1、概述

Zuul 作为路由网关组件、隶属Netfix

SpringCloud微服务架构图:

通过图可以看到、zuul是整个架构对外的大门、pc端和移动端的请求都要通过Zuul这个网关、然后由网站

来实现鉴权、动态路由等操作、

2、工作原理

话不多说、先来个图

Zuul 是通过Servlet 来实现的, Zuul 通过自定义的Zuu!Servlet 来对请求进行控制。

Zuul 的核心是一系列过滤器,可以在Http 请求的发起和响应返回期间执行一系列的过滤器。

Zuul 包括以下4 种过滤器:

口PRE 过滤器: 它是在请求路由到具体的服务之前执行的,这种类型的过滤器可以做安全验证,例如身份验证、参数验证等。
口ROUTING 过滤器: 它用于将请求路由到具体的微服务实例。在默认情况下,它使用Http Client 进行网络请求。
口POST 过滤器:它是在请求己被路由到微服务后执行的。一般情况下,用作收集统计信息、指标,以及将响应传输到客户端。
口ERROR 过滤器:它是在其他过滤器发生错误时执行的。

3、入门案例

依赖pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>cloud-demo</artifactId>
        <groupId>cn.itcast.demo</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <groupId>cn.itcast.demo</groupId>
    <artifactId>zuul-demo</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
        </dependency>
    </dependencies>
</project>

启动类ZuulDemoApp.java

package www.baidus.zuul;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;

/**
 * @ Author     :ShaoWei Sun.
 * @ Date       :Created in 13:47 2018/12/2
 */
@SpringBootApplication
@EnableZuulProxy //开启Zuul的网关功能
@EnableDiscoveryClient //开启Eureka客客户端发现功能
public class ZuulDemoApp {
    public static void main(String[] args) {
        SpringApplication.run(ZuulDemoApp.class,args);
    }
}

application.yml全局配置

server:
  port: 10010 #服务端口
spring:
  application:
    name: api-gateway #指定服务名

编写路由规则

zuul:
  routes:
    user-service: # 这里是路由id,随意写
      path: /user-service/** # 这里是映射路径
      url: http://127.0.0.1:8081 # 映射路径对应的实际url地址
我们将符合path 规则的一切请求,都代理到 url参数指定的地址

本例中,我们将 /user-service/**开头的请求,代理到http://127.0.0.1:8081

启动测试:http://127.0.0.1:10010/user-service/user/1

4、动态路由Eureka注册中心实例列表(面向服务的路由)

上面的实例中、(将 /user-service/**开头的请求,代理到http://127.0.0.1:8081)

我们把路径对应的服务地址写死了!如果同一服务有多个实例的话,这样做显然就不合理了。

我们应该根据服务的名称,去Eureka注册中心查找 服务对应的所有实例列表,然后进行动态路由才对!

在zuul-service中pom.xml添加Eureka客户端依赖、使网关通过Eureka动态路由到(负载小的)服务器上。

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

zuul-service开启Eureka客户端发现功能

package www.baidus.zuul;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;

/**
 * @ Author     :ShaoWei Sun.
 * @ Date       :Created in 13:47 2018/12/2
 */
@SpringBootApplication
@EnableZuulProxy //开启Zuul的网关功能
@EnableDiscoveryClient //开启Eureka客客户端发现功能
public class ZuulDemoApp {
    public static void main(String[] args) {
        SpringApplication.run(ZuulDemoApp.class,args);
    }
}

添加Eureka配置,获取服务信息 、修改映射文件application.yml

eureka:
  client:
    registry-fetch-interval-seconds: 5 # 获取服务列表的周期:5s
    service-url:
      defaultZone: http://127.0.0.1:10086/eureka,http://127.0.0.1:10087/eureka,http://127.0.0.1:10088/eureka,
  instance:
    prefer-ip-address: true
    ip-address: 127.0.0.1

修改映射配置,通过服务名称获取

zuul:
  routes:
    user-service: # 这里是路由id,随意写
      path: /user-serverss/** # 这里是映射路径
      serviceId: user-service # 指定服务名称

启动测试:http://127.0.0.1:10010/user-serverss/user/1 查看日志

 

 

5、简化的路由配置

zuul:
  routes:
    user-service: /user-service/** # 这里是映射路径

6、默认路由规则

默认情况下,一切服务的映射路径就是服务名本身。

- 例如服务名为:user-service,则默认的映射路径就是:/user-service/**

7、路由前缘

zuul:
  prefix: /ap # 添加路由前缀
  routes:
      user-service: /user-service/** # 这里是映射路径

 路径/ap/user-service/user/1将会被代理到/user-service/user/1

8、过虑器、自定义过虑器

Zuul作为网关的其中一个重要功能,就是实现请求的鉴权。而这个动作我们往往是通过Zuul提供的过滤器来实现的。

ZuulFilter是过滤器的顶级父类。在这里我们看一下其中定义的4个最重要的方法:

public abstract ZuulFilter implements IZuulFilter{

    abstract public String filterType();

    abstract public int filterOrder();
    
    boolean shouldFilter();// 来自IZuulFilter

    Object run() throws ZuulException;// IZuulFilter
}

说明:

filterType:返回字符串,代表过滤器的类型。包含以下4种:

- pre:请求在被路由之前执行
- routing:在路由请求时调用
- post:在routing和errror过滤器之后调用
- error:处理请求时发生错误调用

filterOrder:通过返回的int值来定义过滤器的执行顺序,数字越小优先级越高。
shouldFilter:返回一个Boolean值,判断该过滤器是否需要执行。返回true执行,返回false不执行。
run:过滤器的具体业务逻辑。

过滤器执行生命周期:图解 

正常流程:

请求到达首先会经过pre类型过滤器,而后到达routing类型,进行路由,
请求就到达真正的服务提供者,执行请求,返回结果后,会到达post过滤器。而后返回响应。

异常流程:

- 整个过程中,pre或者routing过滤器出现异常,都会直接进入error过滤器,
再error处理完毕后,会将请求交给POST过滤器,最后返回给用户。
- 如果是error过滤器自己出现异常,最终也会进入POST过滤器,而后返回。
- 如果是POST过滤器出现异常,会跳转到error过滤器,但是与pre和routing不同的时,
请求不会再到达POST过滤器了。

使用场景:

- 请求鉴权:一般放在pre类型,如果发现没有访问权限,直接就拦截了
- 异常处理:一般会在error类型和post类型过滤器中结合来处理。
- 服务调用时长统计:pre和post结合使用。

自定义过滤器:如果请求参数中没token就拦截不放行。

MyFilter.java

package www.baidus.zuul.filter;

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;

/**
 * @ Author     :ShaoWei Sun.
 * @ Date       :Created in 14:15 2018/12/4
 */
@Component
public class MyFilter  extends ZuulFilter {
    @Override
    public String filterType() {
        return "pre";
    }

    @Override
    public int filterOrder() {
        return 1;
    }

    @Override
    public boolean shouldFilter() {
        return true;
    }

    @Override
    public Object run() throws ZuulException {

        //获取上下文资源
        RequestContext currentContext = RequestContext.getCurrentContext();

        //从上下文获取request
        HttpServletRequest request = currentContext.getRequest();

        //获取参数
        String token = request.getParameter("token");

        if (StringUtils.isEmpty(token) || "".equals(token.trim())){
            // 没有token,登录校验失败,拦截不响应
            currentContext.setSendZuulResponse(false);
            //返回401状态码
            currentContext.setResponseStatusCode(401);
        }
        return null;
    }
}

http://127.0.0.1:10010/ap/user-service/user/2

http://127.0.0.1:10010/ap/user-service/user/2?token=lan

9、负载均衡和熔断

Zuul中默认就已经集成了Ribbon负载均衡和Hystix熔断机制。但是所有的超时策略都是走的默认值,
比如熔断超时时间只有1S,很容易就触发了。因此建议我们手动进行配置:
ribbon:
  ConnectTimeout: 250 # 连接超时时间(ms)
  ReadTimeout: 2000 # 通信超时时间(ms)
hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 6000

猜你喜欢

转载自blog.csdn.net/sswqzx/article/details/84782107