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)); } }