Spring Cloud学习——网关:Zuul

什么是Zuul

Zuul 是 Netflix 开源的微服务网关组件,它可以和 Eureka、Ribbon、Hystrix 等组件配合使用。Zuul 的核心是一系列的过滤器 (比如:动态路由)。Spring Cloud Zuul 对 Zuul 进行了整合 ,从而更方便的与 Spring Cloud 一起使用。

Zuul是Spring Cloud全家桶中的微服务API网关。所有从设备或网站来的请求都会经过Zuul到达后端的Netflix应用程序。作为一个边界性质的应用程序,Zuul提供了动态路由、监控、弹性负载和安全功能。

Zuul1 vs Zuul2

Zuul1 是基于 Servlet 框架构建,采用的是阻塞和多线程方式,即一个线程处理一次连接请求,这种方式在内部延迟严重、设备故障较多情况下会引起存活的连接增多和线程增加的情况发生。

在这里插入图片描述
Zuul2 与 Zuul1 最大的区别是它运行在异步和无阻塞框架上(实际上是基于Netty实现的),每个 CPU 核一个线程,处理所有的请求和响应,请求和响应的生命周期是通过事件和回调来处理的,这种方式减少了线程数量,因此开销较小。又由于数据被存储在同一个 CPU 里,可以复用 CPU 级别的缓存,前面提及的延迟和重试风暴问题也通过队列存储连接数和事件数方式减轻了很多(较线程切换来说轻量级很多,自然消耗较小)。这一变化一定会大大提升性能。
在这里插入图片描述
注意:zuul 2.0 版本 Spring Cloud 官方现阶段不打算集成,官方还是推荐使用 Spring Cloud Gateway。

如何使用Zuul

  1. pom加入zuul

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
        </dependency>
    
  2. 增加EnableZuulProxy注解

    @SpringBootApplication
    @EnableZuulProxy
    public class ZuulApplication {
        public static void main(String[] args) {
            SpringApplication.run(ZuulApplication.class, args);
        }
    }
    
  3. 修改appliation.yml

    server:
      port: 8882
    
    spring:
      application:
        name: user
    
    eureka:
      client:
        serviceUrl:
          defaultZone: http://localhost:8880/eureka/
    
  4. 启动项目,我们会在Eureka Server中发现zuul服务,默认访问规则:http://gateway:port/service-id/**

路由配置

Zuul提供了一套简单且强大路由配置策略,利用路由配置我们可以完成对微服务和URL更精确的控制。

  • 重写指定微服务的访问路径:这表示将rest-demo微服务的地址映射到/rest/**路径。

    zuul:
      routes:
        rest-demo: /rest/**
    
  • 忽略指定微服务:使用“*”可忽略所有微服务,多个指定微服务以半角逗号分隔。

    zuul:
    	ignored-services: rest-demo,xxx-service
    
  • 指定path和URL:此例将http://ZUULHOST:ZUULPORT/rest/映射到http://localhost:8000/。同时由于并非用service-id定位服务,所以也无法使用负载均衡功能。

    zuul:
      routes:
        route-name:
          url: http://localhost:8000/
          path: /rest/**
    
  • 即指定path和URL,又保留Zuul的Hystrix、Ribbon特性

    zuul:
      routes:
        route-name: #路由别名,无其他意义,与例1效果一致
          service-id: rest-demo
          path: /rest/
          
    ribbon:
      eureka:
        enable: false #为Ribbon禁用Eureka
    rest-demo:
      ribbon:
        listOfServers: localhost:9000,localhost:9001
    
  • 借助PatternServiceRouteMapper实现路由的正则匹配:此例可以将rest-demo-v1映射为/v1/rest-demo/**。

    @Bean
    public PatternServiceRouteMapper serviceRouteMapper(){
        /**
         * A RegExp Pattern that extract needed information from a service ID. Ex :
         * "(?<name>.*)-(?<version>v.*$)"
         */
        //private Pattern servicePattern;
        /**
         * A RegExp that refer to named groups define in servicePattern. Ex :
         * "${version}/${name}"
         */
        //private String routePattern;
        return new PatternServiceRouteMapper("(?<name>^.+)-(?<version>v.+$)", "${version}/${name}");
    }
    
  • 路由前缀:此时访问Zuul的/api/rest/user/xdlysk会被转发到/rest-demo/user/xdlysk。

    zuul:
      prefix: /api
      strip-prefix: true
      routes:
        rest-demo: /rest/**
    
  • 忽略某些微服务中的某些路径

    zuul:
      ignoredPatterns: /**/user/* #忽略所有包含/user/的地址请求
      routes:
        route-demo:
          service-Id: rest-demo
          path: /rest/**
    

Zuul过滤器

Zuul是围绕一系列Filter展开的,这些Filter在整个HTTP请求过程中执行一连串的操作。各个Filter间没有直接联系,但是都通过RequestContext共享一些状态数据。

以下提供四种标准的Filter类型及其在请求生命周期中所处的位置:

  • PRE Filter:在请求路由到目标之前执行。一般用于请求认证、负载均衡和日志记录。
  • ROUTING Filter:处理目标请求。这里使用Apache HttpClient或Netflix Ribbon构造对目标的HTTP请求。
  • POST Filter:在目标请求返回后执行。一般会在此步骤添加响应头、收集统计和性能数据等。
  • ERROR Filter:整个流程某块出错时执行。

一个请求到来的时候,就要经历preRoute、route、postRoute几个阶段,用官方的图来说明
在这里插入图片描述
我们使用拦截器实现两个功能。

登录验证

filterType: 返回一个字符串代表过滤器的类型,在zuul中定义了四种不同生命周期的过滤器类型,上面已经提到过,简单描述如下:

  • pre:路由之前
  • routing:路由之时
  • post: 路由之后
  • error:发送错误调用

filterOrder: 过滤的顺序。
shouldFilter: 这里可以写逻辑判断,是否要过滤,本文true,永远过滤。
run: 过滤器的具体逻辑。可用很复杂,包括查sql,nosql去判断该请求到底有没有权限访问。

/**
 * @program spring-cloud
 * @description: zuul filter
 * @author: xyhua
 * @create: 2020/01/10 14:57
 */
@Component
public class loginFilter extends ZuulFilter {
    /**
     * 过滤器类型
     * PRE:在请求路由到目标之前执行。一般用于请求认证、负载均衡和日志记录。
     * ROUTING:处理目标请求。这里使用Apache HttpClient或Netflix Ribbon构造对目标的HTTP请求。
     * POST:在目标请求返回后执行。一般会在此步骤添加响应头、收集统计和性能数据等。
     * ERROR:整个流程某块出错时执行。
     * @return
     */
    @Override
    public String filterType() {
        return PRE_TYPE;
    }

    /**
     * 拦截器顺序 越小越靠前
     * @return
     */
    @Override
    public int filterOrder() {
        return 4;
    }

    /**
     * 拦截器是否生效
     * @return
     */
    @Override
    public boolean shouldFilter() {
        RequestContext requestContext = RequestContext.getCurrentContext();
        HttpServletRequest request = requestContext.getRequest();

        //根据ACL列表筛选
        if("/fs-order/order/getId".equalsIgnoreCase(request.getRequestURI())) {
            return true;
        }
        return false;
    }

    /**
     * 处理逻辑
     * @return
     * @throws ZuulException
     */
    @Override
    public Object run() throws ZuulException {
        //从请求上下文获取请求
        RequestContext requestContext = RequestContext.getCurrentContext();
        HttpServletRequest request = requestContext.getRequest();

        //token对象
        String token = request.getHeader("token");
        if(StringUtils.isEmpty(token)) {
            token = request.getParameter("token");
        }

        //登陆校验逻辑
        if(StringUtils.isEmpty(token)) {
            requestContext.setSendZuulResponse(false);
            requestContext.setResponseStatusCode(HttpStatus.SC_UNAUTHORIZED);
        }
        return null;
    }
}

网关限流

使用Guava进行限流控制。

package com.fresh.zuul.filter;

import com.google.common.util.concurrent.RateLimiter;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;

import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.PRE_TYPE;

/**
 * @program spring-cloud
 * @description:
 * @author: xyhua
 * @create: 2020/01/11 17:59
 */
@Component
public class OrderRateLimiterFilter extends ZuulFilter {

    private static final RateLimiter rateLimiter = RateLimiter.create(10000);

    @Override
    public String filterType() {
        return PRE_TYPE;
    }

    @Override
    public int filterOrder() {
        return -4;
    }

    @Override
    public boolean shouldFilter() {
        RequestContext requestContext = RequestContext.getCurrentContext();
        HttpServletRequest request = requestContext.getRequest();

        //只对重要接口做限流
        if("/fs-order/order/getId".equalsIgnoreCase(request.getRequestURI())) {
            return true;
        }
        return false;
    }

    @Override
    public Object run() throws ZuulException {
        //从请求上下文获取请求
        RequestContext requestContext = RequestContext.getCurrentContext();
        if(!rateLimiter.tryAcquire()) {
            requestContext.setSendZuulResponse(false);
            requestContext.setResponseStatusCode(HttpStatus.TOO_MANY_REQUESTS.value());
            try {
                requestContext.getResponse().getWriter().write("token is empty");
            }catch (Exception e){}
        }
        return null;
    }
}

Filter的启用与禁用

我们自己写的Filter可以通过修改shouldFilter()启用或禁用。如果第三方的Filter怎样控制其启用及禁用呢?很简单,通过配置文件就可以做到:

zuul:
  PreRequestLogFilter: #自定义Filter类名
    pre: #Type
      disable: true

Zuul源码分析

首先看下架构图

在这里插入图片描述
在zuul中, 整个请求的过程是这样的,首先将请求给zuulservlet处理,zuulservlet中有一个zuulRunner对象,该对象中初始化了RequestContext:作为存储整个请求的一些数据,并被所有的zuulfilter共享。zuulRunner中还有 FilterProcessor,FilterProcessor作为执行所有的zuulfilter的管理器。FilterProcessor从filterloader 中获取zuulfilter,而zuulfilter是被filterFileManager所加载,并支持groovy热加载,采用了轮询的方式热加载。有了这些filter之后,zuulservelet首先执行的Pre类型的过滤器,再执行route类型的过滤器,最后执行的是post 类型的过滤器,如果在执行这些过滤器有错误的时候则会执行error类型的过滤器。执行完这些过滤器,最终将请求的结果返回给客户端。

在之前已经讲过,如何使用zuul,其中不可缺少的一个步骤就是在程序的启动类加上@EnableZuulProxy,该EnableZuulProxy类代码如下:

@EnableCircuitBreaker
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Import({ZuulProxyMarkerConfiguration.class})
public @interface EnableZuulProxy {
}

我们看到引入了ZuulProxyMarkerConfiguration类,但是只是返回了Marker,只用来做标记。

@Configuration
public class ZuulProxyMarkerConfiguration {
    public ZuulProxyMarkerConfiguration() {
    }

    @Bean
    public ZuulProxyMarkerConfiguration.Marker zuulProxyMarkerBean() {
        return new ZuulProxyMarkerConfiguration.Marker();
    }

    class Marker {
        Marker() {
        }
    }
}

我们在相同的包下找到了ZuulProxyAutoConfiguration类,这个类被加载的条件就是已经加载了Marker类。该类注入了DiscoveryClientRibbonCommandFactoryConfiguration用作负载均衡相关的。注入了一些列的filters,比如PreDecorationFilterRibbonRoutingFilterSimpleHostRoutingFilter,代码如如下:

    @Bean
    @ConditionalOnMissingBean({DiscoveryClientRouteLocator.class})
    public DiscoveryClientRouteLocator discoveryRouteLocator() {
        return new DiscoveryClientRouteLocator(this.server.getServlet().getServletPrefix(), this.discovery, this.zuulProperties, this.serviceRouteMapper, this.registration);
    }

    @Bean
    @ConditionalOnMissingBean({PreDecorationFilter.class})
    public PreDecorationFilter preDecorationFilter(RouteLocator routeLocator, ProxyRequestHelper proxyRequestHelper) {
        return new PreDecorationFilter(routeLocator, this.server.getServlet().getServletPrefix(), this.zuulProperties, proxyRequestHelper);
    }

    @Bean
    @ConditionalOnMissingBean({RibbonRoutingFilter.class})
    public RibbonRoutingFilter ribbonRoutingFilter(ProxyRequestHelper helper, RibbonCommandFactory<?> ribbonCommandFactory) {
        RibbonRoutingFilter filter = new RibbonRoutingFilter(helper, ribbonCommandFactory, this.requestCustomizers);
        return filter;
    }

    @Bean
    @ConditionalOnMissingBean({SimpleHostRoutingFilter.class, CloseableHttpClient.class})
    public SimpleHostRoutingFilter simpleHostRoutingFilter(ProxyRequestHelper helper, ZuulProperties zuulProperties, ApacheHttpClientConnectionManagerFactory connectionManagerFactory, ApacheHttpClientFactory httpClientFactory) {
        return new SimpleHostRoutingFilter(helper, zuulProperties, connectionManagerFactory, httpClientFactory);
    }

    @Bean
    @ConditionalOnMissingBean({SimpleHostRoutingFilter.class})
    public SimpleHostRoutingFilter simpleHostRoutingFilter2(ProxyRequestHelper helper, ZuulProperties zuulProperties, CloseableHttpClient httpClient) {
        return new SimpleHostRoutingFilter(helper, zuulProperties, httpClient);
    }

    @Bean
    @ConditionalOnMissingBean({ServiceRouteMapper.class})
    public ServiceRouteMapper serviceRouteMapper() {
        return new SimpleServiceRouteMapper();
    }

它的父类ZuulServerAutoConfiguration ,引用了一些相关的配置。在缺失zuulServlet 的情况下注入了ZuulServlet,该类是zuul的核心类。

    @Bean
    @ConditionalOnMissingBean(
        name = {"zuulServlet"}
    )
    public ServletRegistrationBean zuulServlet() {
        ServletRegistrationBean<ZuulServlet> servlet = new ServletRegistrationBean(new ZuulServlet(), new String[]{this.zuulProperties.getServletPattern()});
        servlet.addInitParameter("buffer-requests", "false");
        return servlet;
    }

同时也注入了其他的过滤器,比如ServletDetectionFilterDebugFilterServlet30WrapperFilter,这些过滤器都是pre类型的。

    @Bean
    public ServletDetectionFilter servletDetectionFilter() {
        return new ServletDetectionFilter();
    }

    @Bean
    public FormBodyWrapperFilter formBodyWrapperFilter() {
        return new FormBodyWrapperFilter();
    }

    @Bean
    public DebugFilter debugFilter() {
        return new DebugFilter();
    }

    @Bean
    public Servlet30WrapperFilter servlet30WrapperFilter() {
        return new Servlet30WrapperFilter();
    }

它也注入了post类型的,比如 SendResponseFilter,error类型,比如 SendErrorFilter,route类型比如SendForwardFilter,代码如下:

    @Bean
    public SendResponseFilter sendResponseFilter(ZuulProperties properties) {
        return new SendResponseFilter(this.zuulProperties);
    }

    @Bean
    public SendErrorFilter sendErrorFilter() {
        return new SendErrorFilter();
    }

    @Bean
    public SendForwardFilter sendForwardFilter() {
        return new SendForwardFilter();
    }

初始化ZuulFilterInitializer类,将所有的filter 向FilterRegistry注册。

    @Configuration
    protected static class ZuulFilterConfiguration {
        @Autowired
        private Map<String, ZuulFilter> filters;

        protected ZuulFilterConfiguration() {
        }

        @Bean
        public ZuulFilterInitializer zuulFilterInitializer(CounterFactory counterFactory, TracerFactory tracerFactory) {
            FilterLoader filterLoader = FilterLoader.getInstance();
            FilterRegistry filterRegistry = FilterRegistry.instance();
            return new ZuulFilterInitializer(this.filters, counterFactory, tracerFactory, filterLoader, filterRegistry);
        }
    }

FilterRegistry管理了一个ConcurrentHashMap,用作存储过滤器的,并有一些基本的CURD过滤器的方法,代码如下:

public class FilterRegistry {
    private static final FilterRegistry INSTANCE = new FilterRegistry();
    private final ConcurrentHashMap<String, ZuulFilter> filters = new ConcurrentHashMap();

    public static final FilterRegistry instance() {
        return INSTANCE;
    }

    private FilterRegistry() {
    }

    public ZuulFilter remove(String key) {
        return (ZuulFilter)this.filters.remove(key);
    }

    public ZuulFilter get(String key) {
        return (ZuulFilter)this.filters.get(key);
    }

    public void put(String key, ZuulFilter filter) {
        this.filters.putIfAbsent(key, filter);
    }

    public int size() {
        return this.filters.size();
    }

    public Collection<ZuulFilter> getAllFilters() {
        return this.filters.values();
    }
}

FilterLoader类持有FilterRegistryFilterFileManager类持有FilterLoader,所以最终是由FilterFileManager注入 filterFilterRegistry的ConcurrentHashMap的。FilterFileManager到开启了轮询机制,定时的去加载过滤器,代码如下:

  void startPoller() {
        poller = new Thread("GroovyFilterFileManagerPoller") {
            public void run() {
                while (bRunning) {
                    try {
                        sleep(pollingIntervalSeconds * 1000);
                        manageFiles();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        };
        poller.setDaemon(true);
        poller.start();
    }

Zuulservlet作为类似于Spring MVC中的DispatchServlet,起到了前端控制器的作用,所有的请求都由它接管。它的核心代码如下:

   @Override
    public void service(javax.servlet.ServletRequest servletRequest, javax.servlet.ServletResponse servletResponse) throws ServletException, IOException {
        try {
            init((HttpServletRequest) servletRequest, (HttpServletResponse) servletResponse);

            // Marks this request as having passed through the "Zuul engine", as opposed to servlets
            // explicitly bound in web.xml, for which requests will not have the same data attached
            RequestContext context = RequestContext.getCurrentContext();
            context.setZuulEngineRan();

            try {
                preRoute();
            } catch (ZuulException e) {
                error(e);
                postRoute();
                return;
            }
            try {
                route();
            } catch (ZuulException e) {
                error(e);
                postRoute();
                return;
            }
            try {
                postRoute();
            } catch (ZuulException e) {
                error(e);
                return;
            }

        } catch (Throwable e) {
            error(new ZuulException(e, 500, "UNHANDLED_EXCEPTION_" + e.getClass().getName()));
        } finally {
            RequestContext.getCurrentContext().unset();
        }
    }

跟踪init,可以发现这个方法为每个请求生成了RequestContext,RequestContext继承了ConcurrentHashMap<String, Object>,在请求结束时销毁掉该RequestContextRequestContext的生命周期为请求到zuulServlet开始处理,直到请求结束返回结果。
RequestContext类在存储了很多重要的信息,包括HttpServletRequestHttpServletResponsResponseDataStreamResponseStatusCode等。 RequestContext对象在处理请求的过程中,一直存在,所以这个对象为所有Filter共享。

ZuulServletservice方法可知,它是先处理pre类型的处理器,然后在处理route类型的处理器,最后再处理post类型的处理器。

首先来看一看pre的处理过程,它会进入到ZuulRunner,该类的作用是将请求的HttpServletRequestHttpServletRespons放在RequestContext类中,并包装了一个FilterProcessor,代码如下:

    public void preRoute() throws ZuulException {
        FilterProcessor.getInstance().preRoute();
    }

FilterProcessor类为调用filters的类,比如调用pre类型所有的过滤器:

    public void preRoute() throws ZuulException {
        try {
            this.runFilters("pre");
        } catch (ZuulException var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new ZuulException(var3, 500, "UNCAUGHT_EXCEPTION_IN_PRE_FILTER_" + var3.getClass().getName());
        }
    }

跟踪runFilters方法,可以发现,它最终调用了FilterLoadergetFiltersByType方法来获取同一类的过滤器,然后用for循环遍历所有的ZuulFilter,执行了 processZuulFilter方法,跟踪该方法可以发现最终是执行了ZuulFilter的方法,最终返回了该方法返回的Object对象。

route、post类型的过滤器的执行过程和pre执行过程类似。

Zuul默认过滤器

Zuul默认注入的过滤器,它们的执行顺序在FilterConstants类,我们可以先定位在这个类,然后再看这个类的过滤器的执行顺序以及相关的注释,可以很轻松定位到相关的过滤器,也可以直接打开
spring-cloud-netflix-core.jarzuul.filters包,可以看到一些列的filter,现在我以表格的形式,列出默认注入的filter。
在这里插入图片描述
过滤器的order值越小,就越先执行,并且在执行过滤器的过程中,它们共享了一个RequestContext对象,该对象的生命周期贯穿于请求,可以看出优先执行了pre类型的过滤器,并将执行后的结果放在RequestContext中,供后续的filter使用,比如在执行PreDecorationFilter的时候,决定使用哪一个route,它的结果的是放在RequestContext对象中,后续会执行所有的route的过滤器,如果不满足条件就不执行该过滤器的run方法。最终达到了就执行一个route过滤器的run方法。

error类型的过滤器,是在程序发生异常的时候执行的。

post类型的过滤,在默认的情况下,只注入了SendResponseFilter,该类型的过滤器是将最终的请求结果以流的形式输出给客户单。

RibbonRoutingFilter vs SimpleHostRoutingFilter

从名字就可以看出来RibbonRoutingFilter是使用Ribbon请求目标服务。

通过shouldFilter方法来看,当配置serviceId时RibbonRoutingFilter生效。

run方法中构造RibbonCommandContext,并通过RestClientRibbonCommandFactory创建一个RibbonCommand(实际类型为RestClientRibbonCommand)。RestClientRibbonCommand继承AbstractRibbonCommand时所带的泛型参数RestClient具备负载均衡能力。又由于在RestClientRibbonCommand的继承链上出现了HystrixCommand,所以通过该Filter发出的请求实际上就同时集成了Ribbon和Hystrix。

    public String filterType() {
        return "route";
    }

    public int filterOrder() {
        return 10;
    }

    public boolean shouldFilter() {
        RequestContext ctx = RequestContext.getCurrentContext();
        return ctx.getRouteHost() == null && ctx.get("serviceId") != null && ctx.sendZuulResponse();
    }

    public Object run() {
        RequestContext context = RequestContext.getCurrentContext();
        this.helper.addIgnoredHeaders(new String[0]);

        try {
            RibbonCommandContext commandContext = this.buildCommandContext(context);
            ClientHttpResponse response = this.forward(commandContext);
            this.setResponse(response);
            return response;
        } catch (ZuulException var4) {
            throw new ZuulRuntimeException(var4);
        } catch (Exception var5) {
            throw new ZuulRuntimeException(var5);
        }
    }

SimpleHostRoutingFilter是用httpclient进行发送请求的。

    public String filterType() {
        return "route";
    }

    public int filterOrder() {
        return 100;
    }

    public boolean shouldFilter() {
        return RequestContext.getCurrentContext().getRouteHost() != null && RequestContext.getCurrentContext().sendZuulResponse();
    }

    public Object run() {
        RequestContext context = RequestContext.getCurrentContext();
        HttpServletRequest request = context.getRequest();
        MultiValueMap<String, String> headers = this.helper.buildZuulRequestHeaders(request);
        MultiValueMap<String, String> params = this.helper.buildZuulRequestQueryParams(request);
        String verb = this.getVerb(request);
        InputStream requestEntity = this.getRequestBody(request);
        if (this.getContentLength(request) < 0L) {
            context.setChunkedRequestBody();
        }

        String uri = this.helper.buildZuulRequestURI(request);
        this.helper.addIgnoredHeaders(new String[0]);

        try {
            CloseableHttpResponse response = this.forward(this.httpClient, verb, uri, request, headers, params, requestEntity);
            this.setResponse(response);
            return null;
        } catch (Exception var9) {
            throw new ZuulRuntimeException(var9);
        }
    }

高可用

一般生产环境需要将多个 Zuul 节点注册到 Eureka Server 上,就可以实现 Zuul 的高可用。事实上,这种情况下的高可用和其他服务做高可用(例如:Eurka Server 集群)的方案没有什么区别。当 Zuul 客户端注册到 Eureka Server 上时,Zuul 客户端会自动从 Eureka Server 查询 Zuul Server 列表,然后使用负载均衡组件(例如: Ribbon)请求 Zuul 集群。另外的方式也可以使用 Nginx 或者硬件 F5 的来实现。

安全性

Spring Cloud 的微服务化后,一般可以使用 Spring Cloud Security 结合 OAuth2.0,生成的 Token 采用 JWT 来验证票据,但 Spring Cloud Security 暂时还不支持 OpenID Connect 协议。Zuul 将自己注册为 Eureka 服务治理下,同时也从 Eureka 服务治理中获得所有其他微服务的实例信息。通过搭建独立的 OAuth2 认证授权服务,将微服务单独剥离出来,这些认证与微服务自己的业务并没有太大的关系,所以这些功能完全可以独立成一个单独的服务存在。独立出来之后,并不是给每个微服务调用(业务服务一般在内网),而是通过 API网关进行统一调用,来对微服务接口做前置过滤,实现对分布式系统中的其他的微服务接口的拦截和安全校验。

Zuul 整合 OAuth2.0 认证授权

Zuul 整合 OAuth2.0 有两种思路,一种是授权服务器采用 JwtToken 统一在网关层使用公钥验证票据,判断权限等操作;另一种是让资源端处理,网关只做路由转发。

之后会进行补充

发布了44 篇原创文章 · 获赞 9 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/hxyascx/article/details/103892360