springcloud原理分析——gateway

在说原理前,先看看一个请求下来在gateway中会发生什么

其中红字的做一下说明:

  1. org.springframework.web.reactive.DispatcherHandler :接收到请求,匹配 HandlerMapping ,此处会匹配到 RoutePredicateHandlerMapping 。
  2. org.springframework.cloud.gateway.handler.RoutePredicateHandlerMapping :接收到请求,匹配 Route 。
  3. org.springframework.cloud.gateway.handler.FilteringWebHandler :获得 Route 的 GatewayFilter 数组,创建 GatewayFilterChain 处理请求。

整体流程:

请求先进入 Gateway Handler mappeing 中解析出对应的路由 Route 和 Predicates

再进入 Gateway Web Handler 中转发到不同的服务

在发送到不同的服务之前和之后都有对应的过滤器来对请求进行处理。

再具体点的流程图:

其中路由到某个服务是根据配置中心的注册表找到相应的地址,然后使用ribbon进行负载均衡路由到相应的服务地址。

原理简要分析:

该篇源码分析是参考:https://blog.csdn.net/white_bird_shit/article/details/107476650

5.1 入口(初始化自动配置类)

查看gateway core包的Spring.factories文件

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
#用来验证项目中是否存在DispatcherServlet(SpringMvc使用,webFlux中不能存在) 是否不存在DispatcherHandler(WebFlux使用)
org.springframework.cloud.gateway.config.GatewayClassPathWarningAutoConfiguration,\
#核心配置类 配置gateway Route Filter 等相关bean
org.springframework.cloud.gateway.config.GatewayAutoConfiguration,\
#负载均衡配置
org.springframework.cloud.gateway.config.GatewayLoadBalancerClientAutoConfiguration,\
org.springframework.cloud.gateway.config.GatewayMetricsAutoConfiguration,\
#缓存相关配置
org.springframework.cloud.gateway.config.GatewayRedisAutoConfiguration,\
#服务发现相关配置 gateway支持从注册中心查询服务并生成对应路由
org.springframework.cloud.gateway.discovery.GatewayDiscoveryClientAutoConfiguration

org.springframework.boot.env.EnvironmentPostProcessor=\
org.springframework.cloud.gateway.config.GatewayEnvironmentPostProcessor

(在项目启动时监测是否有 org.springframework.web.servlet.DispatcherServlet 这个类是SpringMvc使用,不能在Gateway中使用,因为Gateway是基于WebFlux的,同理,项目中必须有 org.springframework.web.reactive.DispatcherHandler

这里我们只需要关注三个:1、GatewayAutoConfiguration  2、GatewayLoadBalancerClientAutoConfiguration(负载均衡)3、GatewayDiscoveryClientAutoConfiguration(获取注册中心的信息)

1、GatewayAutoConfiguration

gateway核心配置类,在此配置类中注入了Gateway相关的路由,过滤器相关bean

5.1.2.1 Route的加载过程

5.1.2.1.1 PropertiesRouteDefinitionLocator

从配置文件中获取路由信息,此时返回的是一个RouteDefinition类

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package org.springframework.cloud.gateway.config;

import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionLocator;
import reactor.core.publisher.Flux;

public class PropertiesRouteDefinitionLocator implements RouteDefinitionLocator {
    private final GatewayProperties properties;

    public PropertiesRouteDefinitionLocator(GatewayProperties properties) {
        this.properties = properties;
    }

    public Flux<RouteDefinition> getRouteDefinitions() {
        //这里调用的GatewayProperties中的getRoutes方法,也就是读取了配置文件中的路由信息
        return Flux.fromIterable(this.properties.getRoutes());
    }
}

5.1.2.1.2 RouteDefinitionRouteLocator

讲之前从配置文件获取到的路由定义类(RouteDefinition) 转换为路由类(Route)

    private Route convertToRoute(RouteDefinition routeDefinition) {
        AsyncPredicate<ServerWebExchange> predicate = this.combinePredicates(routeDefinition);
        List<GatewayFilter> gatewayFilters = this.getFilters(routeDefinition);
        return ((AsyncBuilder)Route.async(routeDefinition).asyncPredicate(predicate).replaceFilters(gatewayFilters)).build();
    }

5.1.2.1.3 CompositeRouteDefinitionLocator

这个类是对RouteDefinitionLocator的包装,就是从 PropertiesRouteDefinitionLocator(配置文件中读取) InMemoryRouteDefinitionRepository(内存中读取) CachingRouteDefinitionLocator(缓存中读取)

DiscoveryClientRouteDefinitionLocator(注册中心服务发现中获取路由)

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package org.springframework.cloud.gateway.route;

import reactor.core.publisher.Flux;

public class CompositeRouteDefinitionLocator implements RouteDefinitionLocator {
    private final Flux<RouteDefinitionLocator> delegates;

    public CompositeRouteDefinitionLocator(Flux<RouteDefinitionLocator> delegates) {
        this.delegates = delegates;
    }

    public Flux<RouteDefinition> getRouteDefinitions() {
        //调用RouteDefinitionLocator的各个实现类的getRouteDefinitions获取路由定义
        return this.delegates.flatMap(RouteDefinitionLocator::getRouteDefinitions);
    }
}

5.1.2.1.4 CachingRouteLocator

是对RouteLocator的封装,直接从内存中读取路由信息

  public CachingRouteLocator(RouteLocator delegate) {
        this.delegate = delegate;
        this.routes = CacheFlux.lookup(this.cache, "routes", Route.class).onCacheMissResume(() -> {
            return this.delegate.getRoutes().sort(AnnotationAwareOrderComparator.INSTANCE);
        });
    }

    public Flux<Route> getRoutes() {
        return this.routes;
    }

5.1.2.1.5 InMemoryRouteDefinitionRepository

默认可以从内存中获取路由,或者可以自己实现 RouteDefinitionRepository,从数据库等媒介中读取路由信息

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package org.springframework.cloud.gateway.route;

import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import org.springframework.cloud.gateway.support.NotFoundException;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

public class InMemoryRouteDefinitionRepository implements RouteDefinitionRepository {
    private final Map<String, RouteDefinition> routes = Collections.synchronizedMap(new LinkedHashMap());

    public InMemoryRouteDefinitionRepository() {
    }

    public Mono<Void> save(Mono<RouteDefinition> route) {
        return route.flatMap((r) -> {
            this.routes.put(r.getId(), r);
            return Mono.empty();
        });
    }

    public Mono<Void> delete(Mono<String> routeId) {
        return routeId.flatMap((id) -> {
            if (this.routes.containsKey(id)) {
                this.routes.remove(id);
                return Mono.empty();
            } else {
                return Mono.defer(() -> {
                    return Mono.error(new NotFoundException("RouteDefinition not found: " + routeId));
                });
            }
        });
    }

    public Flux<RouteDefinition> getRouteDefinitions() {
        return Flux.fromIterable(this.routes.values());
    }
}

5.1.3 GatewayLoadBalancerClientAutoConfiguration

负载均衡过滤器配置

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package org.springframework.cloud.gateway.config;

import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.cloud.gateway.filter.LoadBalancerClientFilter;
import org.springframework.cloud.netflix.ribbon.RibbonAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.DispatcherHandler;

@Configuration
@ConditionalOnClass({LoadBalancerClient.class, RibbonAutoConfiguration.class, DispatcherHandler.class})
@AutoConfigureAfter({RibbonAutoConfiguration.class})
@EnableConfigurationProperties({LoadBalancerProperties.class})
public class GatewayLoadBalancerClientAutoConfiguration {
    public GatewayLoadBalancerClientAutoConfiguration() {
    }

    @Bean
    @ConditionalOnBean({LoadBalancerClient.class})
    @ConditionalOnMissingBean({LoadBalancerClientFilter.class})
    public LoadBalancerClientFilter loadBalancerClientFilter(LoadBalancerClient client, LoadBalancerProperties properties) {
        return new LoadBalancerClientFilter(client, properties);
    }
}

注入LoadBalancerClientFilter 过滤器,引入RibbonLoadBalanceClient (gateway也默认引入了Ribbon)

点进去看下 LoadBalancerClientFilter 的作用

public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        URI url = (URI)exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR);
        String schemePrefix = (String)exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_SCHEME_PREFIX_ATTR);
        if (url != null && ("lb".equals(url.getScheme()) || "lb".equals(schemePrefix))) {
            ServerWebExchangeUtils.addOriginalRequestUrl(exchange, url);
            log.trace("LoadBalancerClientFilter url before: " + url);
            ServiceInstance instance = this.choose(exchange);
            if (instance == null) {
                String msg = "Unable to find instance for " + url.getHost();
                if (this.properties.isUse404()) {
                    throw new LoadBalancerClientFilter.FourOFourNotFoundException(msg);
                } else {
                    throw new NotFoundException(msg);
                }
            } else {
                URI uri = exchange.getRequest().getURI();
                String overrideScheme = instance.isSecure() ? "https" : "http";
                if (schemePrefix != null) {
                    overrideScheme = url.getScheme();
                }

                URI requestUrl = this.loadBalancer.reconstructURI(new LoadBalancerClientFilter.DelegatingServiceInstance(instance, overrideScheme), uri);
                log.trace("LoadBalancerClientFilter url chosen: " + requestUrl);
                exchange.getAttributes().put(ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR, requestUrl);
                return chain.filter(exchange);
            }
        } else {
            return chain.filter(exchange);
        }
    }

这个过滤器的作用就是判断路由的uri是不是包含 lb:开头

如果是,就使用ribbon负载均衡去转发请求

5.1.4 GatewayMetricsAutoConfiguration

注入监控相关filter

5.1.5 GatewayRedisAutoConfiguration

缓存注入

5.1.6 GatewayDiscoveryClientAutoConfiguration

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package org.springframework.cloud.gateway.discovery;

import java.util.ArrayList;
import java.util.List;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.client.discovery.composite.CompositeDiscoveryClientAutoConfiguration;
import org.springframework.cloud.gateway.config.GatewayAutoConfiguration;
import org.springframework.cloud.gateway.filter.FilterDefinition;
import org.springframework.cloud.gateway.filter.factory.RewritePathGatewayFilterFactory;
import org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory;
import org.springframework.cloud.gateway.handler.predicate.PredicateDefinition;
import org.springframework.cloud.gateway.support.NameUtils;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.DispatcherHandler;

@Configuration
@ConditionalOnProperty(
    name = {"spring.cloud.gateway.enabled"},
    matchIfMissing = true
)
@AutoConfigureBefore({GatewayAutoConfiguration.class})
@AutoConfigureAfter({CompositeDiscoveryClientAutoConfiguration.class})
@ConditionalOnClass({DispatcherHandler.class, DiscoveryClient.class})
@EnableConfigurationProperties
public class GatewayDiscoveryClientAutoConfiguration {
    public GatewayDiscoveryClientAutoConfiguration() {
    }

    @Bean
    @ConditionalOnBean({DiscoveryClient.class})
    @ConditionalOnProperty(
        name = {"spring.cloud.gateway.discovery.locator.enabled"}
    )
    public DiscoveryClientRouteDefinitionLocator discoveryClientRouteDefinitionLocator(DiscoveryClient discoveryClient, DiscoveryLocatorProperties properties) {
        return new DiscoveryClientRouteDefinitionLocator(discoveryClient, properties);
    }

    @Bean
    public DiscoveryLocatorProperties discoveryLocatorProperties() {
        DiscoveryLocatorProperties properties = new DiscoveryLocatorProperties();
        properties.setPredicates(initPredicates());
        properties.setFilters(initFilters());
        return properties;
    }

    public static List<PredicateDefinition> initPredicates() {
        ArrayList<PredicateDefinition> definitions = new ArrayList();
        PredicateDefinition predicate = new PredicateDefinition();
        predicate.setName(NameUtils.normalizeRoutePredicateName(PathRoutePredicateFactory.class));
        predicate.addArg("pattern", "'/'+serviceId+'/**'");
        definitions.add(predicate);
        return definitions;
    }

    public static List<FilterDefinition> initFilters() {
        ArrayList<FilterDefinition> definitions = new ArrayList();
        FilterDefinition filter = new FilterDefinition();
        filter.setName(NameUtils.normalizeFilterFactoryName(RewritePathGatewayFilterFactory.class));
        String regex = "'/' + serviceId + '/(?<remaining>.*)'";
        String replacement = "'/${remaining}'";
        filter.addArg("regexp", regex);
        filter.addArg("replacement", replacement);
        definitions.add(filter);
        return definitions;
    }
}

当接入有注册中心时,并在配置文件中开启 spring.cloud.gateway.enabled 后,gateway会从注册中心中查询所有服务,并创建对应的路由,默认断言是 PathRoutePredicateFactory “pattern”, “’/’+serviceId+’/**’”

5.2 请求处理

5.2.1 DispatcherHandler 请求分发

服务启动,首先进入 DispatcherHandler (类似springmvc的DispatcherServlet) 的 initStrategies 方法,初始化所有的HandlerMapping放入上下文

当有请求进入网关时,同样也是进入DispatcherHandler,DispatcherHandler执行handle方法

 protected void initStrategies(ApplicationContext context) {
     	//获取所有HandlerMapping接口的实现类
        Map<String, HandlerMapping> mappingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
     	//转换成List
        ArrayList<HandlerMapping> mappings = new ArrayList(mappingBeans.values());
     	//排序(Order接口)
        AnnotationAwareOrderComparator.sort(mappings);
     	//将转换后的Mappings转换为一个不能修改,只读的List
        this.handlerMappings = Collections.unmodifiableList(mappings);
     	//获取所有HandlerAdapter的实现类
        Map<String, HandlerAdapter> adapterBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false);
     	//转换为list
        this.handlerAdapters = new ArrayList(adapterBeans.values());
     	//排序
        AnnotationAwareOrderComparator.sort(this.handlerAdapters);
     	//获取所有HandlerResultHandler的实现类
        Map<String, HandlerResultHandler> beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerResultHandler.class, true, false);
     	//转为list
        this.resultHandlers = new ArrayList(beans.values());
     	//排序
        AnnotationAwareOrderComparator.sort(this.resultHandlers);
    }

	//请求的处理方法
    public Mono<Void> handle(ServerWebExchange exchange) {
        //如果初始化的方法里handlerMappings不为空,就执行handlerMapping的getHandler方法
        return this.handlerMappings == null ? this.createNotFoundError() : Flux.fromIterable(this.handlerMappings).concatMap((mapping) -> {
            return mapping.getHandler(exchange);
        }).next().switchIfEmpty(this.createNotFoundError()).flatMap((handler) -> {
            return this.invokeHandler(exchange, handler);
        }).flatMap((result) -> {
            return this.handleResult(exchange, result);
        });
    }

进入handlerMapping实现类AbstractHandlerMappinggetHandler方法

这个方法是用来获取所有的handler的

public Mono<Object> getHandler(ServerWebExchange exchange) {
    	//函数式编程获取getHandlerInternal
        return this.getHandlerInternal(exchange).map((handler) -> {
            if (this.logger.isDebugEnabled()) {
                this.logger.debug(exchange.getLogPrefix() + "Mapped to " + handler);
            }

            if (CorsUtils.isCorsRequest(exchange.getRequest())) {
                CorsConfiguration configA = this.corsConfigurationSource.getCorsConfiguration(exchange);
                CorsConfiguration configB = this.getCorsConfiguration(handler, exchange);
                CorsConfiguration config = configA != null ? configA.combine(configB) : configB;
                if (!this.getCorsProcessor().process(config, exchange) || CorsUtils.isPreFlightRequest(exchange.getRequest())) {
                    return REQUEST_HANDLED_HANDLER;
                }
            }

            return handler;
        });
    }
//抽象方法 由每个继承类定义具体的实现
protected abstract Mono<?> getHandlerInternal(ServerWebExchange var1);

5.2.2 RoutePredicateHandlerMapping 获取路由

再看 getHandlerInternal 方法

进入AbstractHandlerMapping的实现类 RoutePredicateHandlerMapping

这个类是通过断言来过滤符合条件的路由,并转发到处理类

protected Mono<?> getHandlerInternal(ServerWebExchange exchange) {
    //判断请求的端口是否是健康检查端口
        if (this.managmentPort != null && exchange.getRequest().getURI().getPort() == this.managmentPort) {
            return Mono.empty();
        } else {
            //把RoutePredicateHandlerMapping这个handlerMaping放入exchange上下文中
            exchange.getAttributes().put(ServerWebExchangeUtils.GATEWAY_HANDLER_MAPPER_ATTR, this.getSimpleName());
            //lookupRoute过滤出符合处理请求的路由
            return this.lookupRoute(exchange).flatMap((r) -> {
                exchange.getAttributes().remove(ServerWebExchangeUtils.GATEWAY_PREDICATE_ROUTE_ATTR);
                if (this.logger.isDebugEnabled()) {
                    this.logger.debug("Mapping [" + this.getExchangeDesc(exchange) + "] to " + r);
                }
				//把符合条件的路由放入exchange上下文中
                exchange.getAttributes().put(ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR, r);
                //交给webHandler处理
                return Mono.just(this.webHandler);
            }).switchIfEmpty(Mono.empty().then(Mono.fromRunnable(() -> {
                exchange.getAttributes().remove(ServerWebExchangeUtils.GATEWAY_PREDICATE_ROUTE_ATTR);
                if (this.logger.isTraceEnabled()) {
                    this.logger.trace("No RouteDefinition found for [" + this.getExchangeDesc(exchange) + "]");
                }

            })));
        }
    }

5.2.3 FilteringWebHandler 过滤

上文中获取到路由之后,就需要对请求进行过滤处理

除了全局过滤器外,还要获取路由中定义的网关过滤器

//构造函数中对全局过滤器进行处理
public FilteringWebHandler(List<GlobalFilter> globalFilters) {
    this.globalFilters = loadFilters(globalFilters);
}

//处理全局过滤器
private static List<GatewayFilter> loadFilters(List<GlobalFilter> filters) {
    //对GlobalFilter进行包装 如果实现了Ordered接口(有排序),就包装成OrderedGatewayFilter 如果没有实现排序接口,就用gatewayFilter包装
    return (List)filters.stream().map((filter) -> {
        FilteringWebHandler.GatewayFilterAdapter gatewayFilter = new FilteringWebHandler.GatewayFilterAdapter(filter);
        if (filter instanceof Ordered) {
            int order = ((Ordered)filter).getOrder();
            return new OrderedGatewayFilter(gatewayFilter, order);
        } else {
            return gatewayFilter;
        }
    }).collect(Collectors.toList());
}

//过滤链处理
public Mono<Void> handle(ServerWebExchange exchange) {
    //获取exchange上下文中的route路由信息
    Route route = (Route)exchange.getRequiredAttribute(ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR);
    //获取路由中的过滤器
    List<GatewayFilter> gatewayFilters = route.getFilters();
    //全局过滤器
    List<GatewayFilter> combined = new ArrayList(this.globalFilters);
    //全局过滤器加上路由中的过滤器
    combined.addAll(gatewayFilters);
    //排序
    AnnotationAwareOrderComparator.sort(combined);
    if (logger.isDebugEnabled()) {
        logger.debug("Sorted gatewayFilterFactories: " + combined);
    }

    //递归调用此类中的内部类DefaultGatewayFilterChain过滤器链进行过滤处理
    return (new FilteringWebHandler.DefaultGatewayFilterChain(combined)).filter(exchange);
}


递归调用

private static class DefaultGatewayFilterChain implements GatewayFilterChain {
        private final int index;
        private final List<GatewayFilter> filters;

        public DefaultGatewayFilterChain(List<GatewayFilter> filters) {
            this.filters = filters;
            this.index = 0;
        }

        private DefaultGatewayFilterChain(FilteringWebHandler.DefaultGatewayFilterChain parent, int index) {
            this.filters = parent.getFilters();
            this.index = index;
        }

        public List<GatewayFilter> getFilters() {
            return this.filters;
        }

        public Mono<Void> filter(ServerWebExchange exchange) {
            return Mono.defer(() -> {
                if (this.index < this.filters.size()) {
                    GatewayFilter filter = (GatewayFilter)this.filters.get(this.index);
                    FilteringWebHandler.DefaultGatewayFilterChain chain = new FilteringWebHandler.DefaultGatewayFilterChain(this, this.index + 1);
                    return filter.filter(exchange, chain);
                } else {
                    return Mono.empty();
                }
            });
        }
    }

5.2.4 转发请求

转发请求由两个全局过滤器实现

NettyRoutingFilter 和 LoadBalancerClientFilter

5.2.4.1 LoadBalancerClientFilter

如果路由的uri是lb开头,就会进入负载均衡从注册中心获取地址

否则进入下一个过滤器

public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        URI url = (URI)exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR);
        String schemePrefix = (String)exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_SCHEME_PREFIX_ATTR);
        if (url != null && ("lb".equals(url.getScheme()) || "lb".equals(schemePrefix))) {
            ServerWebExchangeUtils.addOriginalRequestUrl(exchange, url);
            log.trace("LoadBalancerClientFilter url before: " + url);
            ServiceInstance instance = this.choose(exchange);
            if (instance == null) {
                String msg = "Unable to find instance for " + url.getHost();
                if (this.properties.isUse404()) {
                    throw new LoadBalancerClientFilter.FourOFourNotFoundException(msg);
                } else {
                    throw new NotFoundException(msg);
                }
            } else {
                URI uri = exchange.getRequest().getURI();
                String overrideScheme = instance.isSecure() ? "https" : "http";
                if (schemePrefix != null) {
                    overrideScheme = url.getScheme();
                }

                URI requestUrl = this.loadBalancer.reconstructURI(new LoadBalancerClientFilter.DelegatingServiceInstance(instance, overrideScheme), uri);
                log.trace("LoadBalancerClientFilter url chosen: " + requestUrl);
                exchange.getAttributes().put(ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR, requestUrl);
                return chain.filter(exchange);
            }
        } else {
            return chain.filter(exchange);
        }
    }

5.2.4.2 NettyRoutingFilter

如果是http开头或者https开头就通过这个过滤器来转发请求

 public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        URI requestUrl = (URI)exchange.getRequiredAttribute(ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR);
        String scheme = requestUrl.getScheme();
        if (!ServerWebExchangeUtils.isAlreadyRouted(exchange) && ("http".equals(scheme) || "https".equals(scheme))) {
            ServerWebExchangeUtils.setAlreadyRouted(exchange);
            ServerHttpRequest request = exchange.getRequest();
            HttpMethod method = HttpMethod.valueOf(request.getMethodValue());
            String url = requestUrl.toString();
            HttpHeaders filtered = HttpHeadersFilter.filterRequest((List)this.headersFilters.getIfAvailable(), exchange);
            DefaultHttpHeaders httpHeaders = new DefaultHttpHeaders();
            filtered.forEach(httpHeaders::set);
            String transferEncoding = request.getHeaders().getFirst("Transfer-Encoding");
            boolean chunkedTransfer = "chunked".equalsIgnoreCase(transferEncoding);
            boolean preserveHost = (Boolean)exchange.getAttributeOrDefault(ServerWebExchangeUtils.PRESERVE_HOST_HEADER_ATTRIBUTE, false);
            Flux<HttpClientResponse> responseFlux = ((RequestSender)this.httpClient.chunkedTransfer(chunkedTransfer).request(method).uri(url)).send((req, nettyOutbound) -> {
                req.headers(httpHeaders);
                if (preserveHost) {
                    String host = request.getHeaders().getFirst("Host");
                    req.header("Host", host);
                }

                return nettyOutbound.options(SendOptions::flushOnEach).send(request.getBody().map((dataBuffer) -> {
                    return ((NettyDataBuffer)dataBuffer).getNativeBuffer();
                }));
            }).responseConnection((res, connection) -> {
                ServerHttpResponse response = exchange.getResponse();
                HttpHeaders headers = new HttpHeaders();
                res.responseHeaders().forEach((entry) -> {
                    headers.add((String)entry.getKey(), (String)entry.getValue());
                });
                String contentTypeValue = headers.getFirst("Content-Type");
                if (StringUtils.hasLength(contentTypeValue)) {
                    exchange.getAttributes().put("original_response_content_type", contentTypeValue);
                }

                HttpStatus status = HttpStatus.resolve(res.status().code());
                if (status != null) {
                    response.setStatusCode(status);
                } else {
                    if (!(response instanceof AbstractServerHttpResponse)) {
                        throw new IllegalStateException("Unable to set status code on response: " + res.status().code() + ", " + response.getClass());
                    }

                    ((AbstractServerHttpResponse)response).setStatusCodeValue(res.status().code());
                }

                HttpHeaders filteredResponseHeaders = HttpHeadersFilter.filter((List)this.headersFilters.getIfAvailable(), headers, exchange, Type.RESPONSE);
                if (!filteredResponseHeaders.containsKey("Transfer-Encoding") && filteredResponseHeaders.containsKey("Content-Length")) {
                    response.getHeaders().remove("Transfer-Encoding");
                }

                exchange.getAttributes().put(ServerWebExchangeUtils.CLIENT_RESPONSE_HEADER_NAMES, filteredResponseHeaders.keySet());
                response.getHeaders().putAll(filteredResponseHeaders);
                exchange.getAttributes().put(ServerWebExchangeUtils.CLIENT_RESPONSE_ATTR, res);
                exchange.getAttributes().put(ServerWebExchangeUtils.CLIENT_RESPONSE_CONN_ATTR, connection);
                return Mono.just(res);
            });
            if (this.properties.getResponseTimeout() != null) {
                responseFlux = responseFlux.timeout(this.properties.getResponseTimeout(), Mono.error(new TimeoutException("Response took longer than timeout: " + this.properties.getResponseTimeout()))).onErrorMap(TimeoutException.class, (th) -> {
                    return new ResponseStatusException(HttpStatus.GATEWAY_TIMEOUT, (String)null, th);
                });
            }

            return responseFlux.then(chain.filter(exchange));
        } else {
            return chain.filter(exchange);
        }
    }

至此,简单的源码分析到此结束。

其实对于源码,个人认为一篇文章是不足以说明什么问题,一篇文章只能在极大的功能中找到几个核心的功能进行简单的说明,想要真正的认识到一个组件/框架的原理需要的是更多的研究。该篇只是对于请求经过gateway时做了哪些最核心的功能,其中分析的比较浅显。等有时间会对源码进行一个更加深入的解析。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值