匹配到路由后,PreDecorationFilter如何设置RequestContext请求上下文
//----------PreDecorationFilter前置过滤器 @Override public Object run() { RequestContext ctx = RequestContext.getCurrentContext(); final String requestURI = this.urlPathHelper.getPathWithinApplication(ctx.getRequest()); Route route = this.routeLocator.getMatchingRoute(requestURI); //找到匹配的路由 //----------------到上面为止是已经分析过的,根据requestURI找到匹配的Route信息 // ==== 匹配到路由信息 if (route != null) { String location = route.getLocation(); if (location != null) { ctx.put(REQUEST_URI_KEY, route.getPath());//RequestContext设置 requestURI:路由的pattern路径 ctx.put(PROXY_KEY, route.getId());//RequestContext设置 proxy:路由id //设置需要忽略的敏感头信息,要么用全局默认的,要么用路由自定义的 if (!route.isCustomSensitiveHeaders()) { this.proxyRequestHelper .addIgnoredHeaders(this.properties.getSensitiveHeaders().toArray(new String[0])); } else { this.proxyRequestHelper.addIgnoredHeaders(route.getSensitiveHeaders().toArray(new String[0])); } //设置重试信息 if (route.getRetryable() != null) { ctx.put(RETRYABLE_KEY, route.getRetryable()); } //如果location是 http/https开头的,RequestContext设置 routeHost:URL //如果location是 forward:开头的,RequestContext设置 forward信息、routeHost:null //其它 RequestContext设置 serviceId、routeHost:null、X-Zuul-ServiceId if (location.startsWith(HTTP_SCHEME+":") || location.startsWith(HTTPS_SCHEME+":")) { ctx.setRouteHost(getUrl(location)); ctx.addOriginResponseHeader(SERVICE_HEADER, location); } else if (location.startsWith(FORWARD_LOCATION_PREFIX)) { ctx.set(FORWARD_TO_KEY, StringUtils.cleanPath(location.substring(FORWARD_LOCATION_PREFIX.length()) + route.getPath())); ctx.setRouteHost(null); return null; } else { // set serviceId for use in filters.route.RibbonRequest ctx.set(SERVICE_ID_KEY, location); ctx.setRouteHost(null); ctx.addOriginResponseHeader(SERVICE_ID_HEADER, location); } //是否添加代理头信息 X-Forwarded-For if (this.properties.isAddProxyHeaders()) { addProxyHeaders(ctx, route); String xforwardedfor = ctx.getRequest().getHeader(X_FORWARDED_FOR_HEADER); String remoteAddr = ctx.getRequest().getRemoteAddr(); if (xforwardedfor == null) { xforwardedfor = remoteAddr; } else if (!xforwardedfor.contains(remoteAddr)) { // Prevent duplicates xforwardedfor += ", " + remoteAddr; } ctx.addZuulRequestHeader(X_FORWARDED_FOR_HEADER, xforwardedfor); } //是否添加Host头信息 if (this.properties.isAddHostHeader()) { ctx.addZuulRequestHeader(HttpHeaders.HOST, toHostHeader(ctx.getRequest())); } } } // ==== 没有匹配到路由信息 else { log.warn("No route found for uri: " + requestURI); String fallBackUri = requestURI; String fallbackPrefix = this.dispatcherServletPath; // default fallback // servlet is // DispatcherServlet if (RequestUtils.isZuulServletRequest()) { // remove the Zuul servletPath from the requestUri log.debug("zuulServletPath=" + this.properties.getServletPath()); fallBackUri = fallBackUri.replaceFirst(this.properties.getServletPath(), ""); log.debug("Replaced Zuul servlet path:" + fallBackUri); } else { // remove the DispatcherServlet servletPath from the requestUri log.debug("dispatcherServletPath=" + this.dispatcherServletPath); fallBackUri = fallBackUri.replaceFirst(this.dispatcherServletPath, ""); log.debug("Replaced DispatcherServlet servlet path:" + fallBackUri); } if (!fallBackUri.startsWith("http://www.likecs.com/")) { fallBackUri = "http://www.likecs.com/" + fallBackUri; } String forwardURI = fallbackPrefix + fallBackUri; forwardURI = forwardURI.replaceAll("//", "http://www.likecs.com/"); ctx.set(FORWARD_TO_KEY, forwardURI); } return null; }总结:
只要引入了spring-cloud-starter-zuul就会间接引入Ribbon、Hystrix
路由信息可能是从配置文件中加载的,也可能是通过DiscoveryClient从注册中心加载的
zuul是通过前置过滤器PreDecorationFilter找到与当前requestURI匹配的路由信息,并在RequestContext中设置相关属性的,后续的Route Filter会根据RequestContext中的这些属性判断如何路由转发
Route Filter主要使用 SimpleHostRoutingFilter 和 RibbonRoutingFilter
当RequestContext请求上下文中存在routeHost,即URL直连信息时,使用SimpleHostRoutingFilter简单Host路由
当RequestContext请求上下文中存在serviceId,即服务id时(可能会与注册中心关联获取服务列表,或者读取配置文件中serviceId.ribbon.listOfServers的服务列表),使用RibbonRoutingFilter,会使用Ribbon、Hystrix