• SpringCloud之Gateway原理解析(二)--调用过程


    本文参考了https://www.jianshu.com/p/9b813f6ca4c2 作者很牛啊

    我们第一个关注的类就是DispatcherHandler,这个类提供的handle()方法,封装了我们之后所有的handlerMappings

    这个DispatcherHandler有点想SpringMVC的DispatchServlet,里面也是封装了请求和对应的处理方法的关系

    public class DispatcherHandler implements WebHandler, ApplicationContextAware {
        @Nullable
        private List<HandlerMapping> handlerMappings;
        @Nullable
        private List<HandlerAdapter> handlerAdapters;
        @Nullable
        private List<HandlerResultHandler> resultHandlers;

    还记得上一节我们的Route最后封装到了Flux里,这时在处理请求的时候就会把这些route取出来

    public Mono<Void> handle(ServerWebExchange exchange) {
    
      if (logger.isDebugEnabled()) {
    
       ServerHttpRequest request = exchange.getRequest();
    
       logger.debug("Processing " + request.getMethodValue() + " request for [" + request.getURI() + "]");
    
      }
    
      if (this.handlerMappings == null) {
    
       return Mono.error(HANDLER_NOT_FOUND_EXCEPTION);
    
      }
    
      return Flux.fromIterable(this.handlerMappings)
    
        .concatMap(mapping -> mapping.getHandler(exchange))
    
        .next()
    
        .switchIfEmpty(Mono.error(HANDLER_NOT_FOUND_EXCEPTION))
    
        .flatMap(handler -> invokeHandler(exchange, handler))
    
        .flatMap(result -> handleResult(exchange, result));
    
     }

    之后就到了FilteringWebHandler类,他的handler方法封装了过滤器进去

    public Mono<Void> handle(ServerWebExchange exchange) {
    
      //h获取到当前访问的路由对象
    
      Route route = exchange.getRequiredAttribute(GATEWAY_ROUTE_ATTR);
    
      //获取当前已经存在的 过滤器 也就是配置的默认过滤器
    
      List<GatewayFilter> gatewayFilters = route.getFilters();
    
     //获取全局过滤器
    
      List<GatewayFilter> combined = new ArrayList<>(this.globalFilters);
    
      combined.addAll(gatewayFilters);
    
      //按order排序
    
      AnnotationAwareOrderComparator.sort(combined);
    
      logger.debug("Sorted gatewayFilterFactories: "+ combined);
    
      return new DefaultGatewayFilterChain(combined).filter(exchange);
    
     }

      从这里开始就是调用各个handler的过程了,这其中有几个很重要的filter

      RouteToRequestUrlFilter

    @Override
    
     public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
    
      Route route = exchange.getAttribute(GATEWAY_ROUTE_ATTR);
    
      if (route == null) {
    
       return chain.filter(exchange);
    
      }
    
      log.trace("RouteToRequestUrlFilter start");
    
      // http://localhost:8804/cydOrganization/getOrgTreeList
    
      URI uri = exchange.getRequest().getURI();
    
      boolean encoded = containsEncodedParts(uri);
    
      // lb://BASE-API-WEB
    
      URI routeUri = route.getUri();
    
      if (hasAnotherScheme(routeUri)) {
    
       // this is a special url, save scheme to special attribute
    
       // replace routeUri with schemeSpecificPart
    
       exchange.getAttributes().put(GATEWAY_SCHEME_PREFIX_ATTR, routeUri.getScheme());
    
       routeUri = URI.create(routeUri.getSchemeSpecificPart());
    
      }
    
      // lb://BASE-API-WEB:8804/cydOrganization/getOrgTreeList
    
      URI requestUrl = UriComponentsBuilder.fromUri(uri)
    
        .uri(routeUri)
    
        .build(encoded)
    
        .toUri();
    
      exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, requestUrl);
    
      return chain.filter(exchange);
    
     }

    最后他将url拼装成了我们需要的,能够做服务发现的url,这时他就会进入LoadBalancerClientFilter 同样我标注url的变化

    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
    
      // lb://BASE-API-WEB:8804/cydOrganization/getOrgTreeList 刚才我们封装完毕的url
    
      URI url = exchange.getAttribute(GATEWAY_REQUEST_URL_ATTR);
    
      String schemePrefix = exchange.getAttribute(GATEWAY_SCHEME_PREFIX_ATTR);
    
      if (url == null || (!"lb".equals(url.getScheme()) && !"lb".equals(schemePrefix))) {
    
       return chain.filter(exchange);
    
      }
    
      //preserve the original url
    
      addOriginalRequestUrl(exchange, url);
    
      log.trace("LoadBalancerClientFilter url before: " + url);
    
      // RibbonServer{serviceId='BASE-API-WEB', server=192.168.47.1:12993, secure=false, metadata={}}
    
      final ServiceInstance instance = loadBalancer.choose(url.getHost());
    
      if (instance == null) {
    
       throw new NotFoundException("Unable to find instance for " + url.getHost());
    
      }
    
      // http://localhost:8804/cydOrganization/getOrgTreeList
    
      URI uri = exchange.getRequest().getURI();
    
      // if the `lb:<scheme>` mechanism was used, use `<scheme>` as the default,
    
      // if the loadbalancer doesn't provide one.
    
      String overrideScheme = null;
    
      if (schemePrefix != null) {
    
       overrideScheme = url.getScheme();
    
      }
    
      // http://192.168.47.1:12993/cydOrganization/getOrgTreeList 到这时 这个地址已经是正确的访问地址了。
    
      URI requestUrl = loadBalancer.reconstructURI(new DelegatingServiceInstance(instance, overrideScheme), uri);
    
      log.trace("LoadBalancerClientFilter url chosen: " + requestUrl);
    
      exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, requestUrl);
    
      return chain.filter(exchange);
    
     }

      最后进入NettyRoutingFilter 这个filter真正做请求的发送,他使用HttpClient进行请求的发送。

      

    public class NettyRoutingFilter implements GlobalFilter, Ordered {
    
     private final HttpClient httpClient;
    
     private final ObjectProvider<List<HttpHeadersFilter>> headersFilters;
    
     public NettyRoutingFilter(HttpClient httpClient,
    
       ObjectProvider<List<HttpHeadersFilter>> headersFilters) {
    
      this.httpClient = httpClient;
    
      this.headersFilters = headersFilters;
    
     }
    
     @Override
    
     public int getOrder() {
    
      return Ordered.LOWEST_PRECEDENCE;
    
     }
    
     @Override
    
     public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { 
    
    // http://192.168.47.1:12993/cydOrganization/getOrgTreeList 我们刚才处理好的url
    
      URI requestUrl = exchange.getRequiredAttribute(GATEWAY_REQUEST_URL_ATTR);
    
      String scheme = requestUrl.getScheme(); 
    
      //必须是 http 或者 https 和没有被路由
    
      if (isAlreadyRouted(exchange) || (!"http".equals(scheme) && !"https".equals(scheme))) {
    
       return chain.filter(exchange);
    
      }
    
     // 设置为已经路由,防止请求重复路由
    
      setAlreadyRouted(exchange);
    
      ServerHttpRequest request = exchange.getRequest();
    
      final HttpMethod method = HttpMethod.valueOf(request.getMethod().toString());
    
      final String url = requestUrl.toString();
    
      HttpHeaders filtered = filterRequest(this.headersFilters.getIfAvailable(),
    
        exchange);
    
      final DefaultHttpHeaders httpHeaders = new DefaultHttpHeaders();
    
      filtered.forEach(httpHeaders::set);
    
      String transferEncoding = request.getHeaders().getFirst(HttpHeaders.TRANSFER_ENCODING);
    
      boolean chunkedTransfer = "chunked".equalsIgnoreCase(transferEncoding);
    
      boolean preserveHost = exchange.getAttributeOrDefault(PRESERVE_HOST_HEADER_ATTRIBUTE, false);
    
     //到这里发送http请求
    
      return this.httpClient.request(method, url, req -> {
    
       final HttpClientRequest proxyRequest = req.options(NettyPipeline.SendOptions::flushOnEach)
    
         .headers(httpHeaders)
    
         .chunkedTransfer(chunkedTransfer)
    
         .failOnServerError(false)
    
         .failOnClientError(false);
    
       if (preserveHost) {
    
        String host = request.getHeaders().getFirst(HttpHeaders.HOST);
    
        proxyRequest.header(HttpHeaders.HOST, host);
    
       }
    
       return proxyRequest.sendHeaders() //I shouldn't need this
    
         .send(request.getBody().map(dataBuffer ->
    
           ((NettyDataBuffer)dataBuffer).getNativeBuffer()));
    
      }).doOnNext(res -> { //接受请求返回结果
    
       ServerHttpResponse response = exchange.getResponse();
    
       // put headers and status so filters can modify the response
    
       HttpHeaders headers = new HttpHeaders();
    
       res.responseHeaders().forEach(entry -> headers.add(entry.getKey(), entry.getValue()));
    
    // 这里可能导致空指针  是我用的版本的bug  SR2版本已经解决 
    
       exchange.getAttributes().put("original_response_content_type", headers.getContentType());
    
       HttpHeaders filteredResponseHeaders = HttpHeadersFilter.filter(
    
         this.headersFilters.getIfAvailable(), headers, exchange, Type.RESPONSE);
    
       response.getHeaders().putAll(filteredResponseHeaders);
    
       HttpStatus status = HttpStatus.resolve(res.status().code());
    
       if (status != null) {
    
        response.setStatusCode(status);
    
       } else if (response instanceof AbstractServerHttpResponse) {
    
        // https://jira.spring.io/browse/SPR-16748
    
        ((AbstractServerHttpResponse) response).setStatusCodeValue(res.status().code());
    
       } else {
    
        throw new IllegalStateException("Unable to set status code on response: " +res.status().code()+", "+response.getClass());
    
       }
    
       // Defer committing the response until all route filters have run
    
       // Put client response as ServerWebExchange attribute and write response later NettyWriteResponseFilter
    
       exchange.getAttributes().put(CLIENT_RESPONSE_ATTR, res);
    
      }).then(chain.filter(exchange));
    
     }
    
    }
  • 相关阅读:
    Android ViewPager用法小结
    HDU1212 Big Number 【同余定理】
    1051. Pop Sequence (25)
    FFmpeg源码结构图
    oracle访问不同用户的表不添加用户名前缀
    window7开启Administrator账户
    Window下对nodejs多版本管理GNVM
    基于Centos7.5搭建Docker环境
    grep与孪生兄弟egrep差异
    Linux编译步骤概述
  • 原文地址:https://www.cnblogs.com/juniorMa/p/14430381.html
Copyright © 2020-2023  润新知