由于我们在之前的所有入门教程中都对HTTP请求使用了简单的接口实现。在实际使用中,我们的HTTP请求要复杂得多。比如我们在使用SpringCloudZuul作为API网关访问网站应用的时候,经常会遇到下面两个很常见的问题:session不能一直重定向上一篇HOST错误文章会帮你分析问题原因并给出解决方案针对这两个常见问题。1.会话维护问题跟踪一个HTTP请求通过Zuul到具体服务,然后返回结果的全过程。我们不难发现,在传输过程中,无论是HTTP请求头信息中的Cookie还是Authorization都没有正确的传递给具体的服务,所以最终没有维护会话状态。那么这些信息丢失在哪里呢?下面就以Zuul的路由转发过滤器为起点一探究竟。下面是RibbonRoutingFilter过滤器的实现片段:publicclassRibbonRoutingFilterextendsZuulFilter{...protectedProxyRequestHelperhelper;@OverridepublicObjectrun(){RequestContextcontext=RequestContext.getCurrentContext();this.helper.addIgnoredHeaders();try{RibbonCommandContextcommandContext=buildCommandContext(context);ClientHttpResponseresponse=forward(commandContext);setResponse(response);returnresponse;}...returnnull;}protectedRibbonCommandContextbuildCommandContext(RequestContextcontext){HttpServletRequestrequest=context.getRequest();MultiValueMapheaders=this.helper.buildMapuulRequestHeaders);MultiValueMapheaders=this.helper.buildMapuulRequestHeaders(re,String>params=this.helper.buildZuulRequestQueryParams(request);...}}这里有三个重要的元素:过滤器的核心逻辑运行函数实现,它调用内部函数buildCommandContext构建上下文内容,buildCommandContext调用helper对象的buildZuulRequestHeaders方法用于处理请求头信息。帮助器对象是ProxyRequestHelper类的一个实例。接下来我们看一下ProxyRequestHelper的实现:publicclassProxyRequestHelper{publicMultiValueMapbuildZuulRequestHeaders(HttpServletRequestrequest){RequestContextcontext=RequestContext.getCurrentContext();MultiValueMapheaders=newHttpHeaders();EnumerationheaderNames=request.getHeaderNames();if(headerNames!=null){while(headerNames.hasMoreElements()){Stringname=headerNames.nextElement();if(isIncludedHeader(name)){Enumerationvalues=request.getHeaders(name);while(values.hasMoreElements()){Stringvalue=values。nextElement();headers.add(name,value);}}}}MapzuulRequestHeaders=context.getZuulRequestHeaders();for(Stringheader:zuulRequestHeaders.keySet()){headers.set(header,zuulRequestHeaders.get(header));}headers.set(HttpHeaders.ACCEPT_ENCODING,"gzip");returnheaders;}publicbooleanisIncludedHeader(StringheaderName){Stringname=headerName.toLowerCase();RequestContextctx=RequestContext.getCurrentContext();if(ctx.containsKey(IGNORED_HEADERS)){Objectobject=ctx.get(IGNORED_HEADERS);if(objectinstanceofCollection&&((Collection>)object).contains(name)){returnfalse;}}...}}从上面的源码中我们可以看到通过buildZuulRequestHeaders构建头信息的方法isIncludedHeader函数判断当前请求的每一个头信息是否在忽略头信息列表中,如果是,则不组织到转发的请求中那么这些需要忽略的header是在哪里初始化的呢?在PRE阶段的PreDecorationFilter过滤器中,我们可以找到答案:Routeroute=this.routeLocator.getMatchingRoute(requestURI);if(route!=null){Stringlocation=route.getLocation();if(location!=null){ctx.put("requestURI",route.getPath());ctx.put("proxy",route.getId());//处理忽略header信息的部分(newString[0]));}else{this.proxyRequestHelper.addIgnoredHeaders(route.getSensitiveHeaders().toArray(newString[0]));}...}从上面的源码中,我们可以看到有一个if/else块调用ProxyRequestHelper的addIgnoredHeaders方法,将需要忽略的信息添加到请求上下文中,供后续ROUTE阶段的过滤器使用。这里的if/else块分别用于处理全局设置的敏感头信息和指定路由设置的敏感头信息。ZuulProperties中定义了全局敏感头信息:@Data@ConfigurationProperties("zuul")publicclassZuulProperties{privateSetsensitiveHeaders=newLinkedHashSet<>(Arrays.asList("Cookie","Set-Cookie","Authorization"));...}所以解决这个问题的思路很简单。我们只需要设置sensitiveHeaders即可。设置方法有两种:1、全局设置:zuul.sensitive-headers=2。指定路由设置:zuul.routes..sensitive-headers=zuul.routes..custom-sensitive-headers=true2.重定向问题使用SpringCloudZuul连接网站时,处理完会话控制问题。往往我们也会遇到下图所示的问题。我们在浏览器中通过Zuul发起登录请求,该请求会被路由到某个WebSite服务。服务完成登录过程后,将重定向到某个主页或欢迎页面。这时候细心的开发者会发现,登录完成后,我们浏览器中的URL中的HOST部分发生了变化,地址变成了具体WebSite服务的地址。这就是我们这一节要分析解决的重定向问题!这个问题的根本原因是SpringCloudZuul没有正确处理HTTP请求头信息中的Host。在Brixton版本中,SpringCloudZuul的PreDecorationFilter过滤器实现完全没有考虑这个问题,更多的定位在RESTAPI的网关。所以如果要在Brixton版本中加入这个功能,相对复杂一些,还好在Camden版本之后,SpringCloudNetflix1.2.xZuul版本增强了这个功能,我们只需要配置属性zuul.add-host-header=true将允许正确处理原始有问题的重定向操作。关于更多Host头信息的处理,读者可以参考本文前面的分析思路,查看PreDecorationFilter过滤器的源码了解更多实现细节。【本文为专栏作家“翟永超”原创稿件,转载请联系作者获得授权】点此查看该作者更多好文