由于我们在之前所有的入门教程中,对于HTTP请求都采用了简单的接口实现。而实际使用过程中,我们的HTTP请求要复杂的多,比如当我们将Spring Cloud Zuul作为API网关接入网站类应用时,往往都会碰到下面这两个非常常见的问题:
本文将帮助大家分析问题原因并给出解决这两个常见问题的方法。
一、会话保持问题
通过跟踪一个HTTP请求经过Zuul到具体服务,再到返回结果的全过程。我们很容易就能发现,在传递的过程中,HTTP请求头信息中的Cookie和Authorization都没有被正确地传递给具体服务,所以最终导致会话状态没有得到保持的现象。
那么这些信息是在哪里丢失的呢?我们从Zuul进行路由转发的过滤器作为起点,来一探究竟。下面是RibbonRoutingFilter过滤器的实现片段:
- public class RibbonRoutingFilter extends ZuulFilter{
- ...
- protected ProxyRequestHelper helper;
-
- @Override
- public Object run() {
- RequestContext context = RequestContext.getCurrentContext();
- this.helper.addIgnoredHeaders();
- try {
- RibbonCommandContext commandContext = buildCommandContext(context);
- ClientHttpResponse response = forward(commandContext);
- setResponse(response);
- return response;
- }
- ...
- return null;
- }
-
- protected RibbonCommandContext buildCommandContext(RequestContext context) {
- HttpServletRequest request = context.getRequest();
- MultiValueMap<String, String> headers = this.helper
- .buildZuulRequestHeaders(request);
- MultiValueMap<String, String> params = this.helper
- .buildZuulRequestQueryParams(request);
- ...
- }
- }
这里有三个重要元素:
- 过滤器的核心逻辑run函数实现,其中调用了内部函数buildCommandContext来构建上下文内容
- 而buildCommandContext中调用了helper对象的buildZuulRequestHeaders方法来处理请求头信息
- helper对象是ProxyRequestHelper类的实例
接下来我们再看看ProxyRequestHelper的实现:
- public class ProxyRequestHelper {
- public MultiValueMap<String, String> buildZuulRequestHeaders(
- HttpServletRequest request) {
- RequestContext context = RequestContext.getCurrentContext();
- MultiValueMap<String, String> headers = new HttpHeaders();
- Enumeration<String> headerNames = request.getHeaderNames();
- if (headerNames != null) {
- while (headerNames.hasMoreElements()) {
- String name = headerNames.nextElement();
- if (isIncludedHeader(name)) {
- Enumeration<String> values = request.getHeaders(name);
- while (values.hasMoreElements()) {
- String value = values.nextElement();
- headers.add(name, value);
- }
- }
- }
- }
- Map<String, String> zuulRequestHeaders = context.getZuulRequestHeaders();
- for (String header : zuulRequestHeaders.keySet()) {
- headers.set(header, zuulRequestHeaders.get(header));
- }
- headers.set(HttpHeaders.ACCEPT_ENCODING, "gzip");
- return headers;
- }
- public boolean isIncludedHeader(String headerName) {
- String name = headerName.toLowerCase();
- RequestContext ctx = RequestContext.getCurrentContext();
- if (ctx.containsKey(IGNORED_HEADERS)) {
- Object object = ctx.get(IGNORED_HEADERS);
- if (object instanceof Collection && ((Collection<?>) object).contains(name)) {
- return false;
- }
- }
- ...
- }
- }
从上述源码中,我们可以看到构建头信息的方法buildZuulRequestHeaders通过isIncludedHeader函数来判断当前请求的各个头信息是否在忽略的头信息清单中,如果是的话就不组织到此次转发的请求中去。那么这些需要忽略的头信息是在哪里初始化的呢?在PRE阶段的PreDecorationFilter过滤器中,我们可以找到答案:
- public class PreDecorationFilter extends ZuulFilter{
- ...
- public Object run() {
- RequestContext ctx = RequestContext.getCurrentContext();
- final String requestURI = this.urlPathHelper.getPathWithinApplication(ctx.getRequest());
- Route route = this.routeLocator.getMatchingRoute(requestURI);
- if (route != null) {
- String location = route.getLocation();
- if (location != null) {
- ctx.put("requestURI", route.getPath());
- ctx.put("proxy", route.getId());
- // 处理忽略头信息的部分
- if (!route.isCustomSensitiveHeaders()) {
- this.proxyRequestHelper.addIgnoredHeaders(
- this.properties.getSensitiveHeaders()
- .toArray(new String[0]));
- } else {
- this.proxyRequestHelper.addIgnoredHeaders(
- route.getSensitiveHeaders()
- .toArray(new String[0]));
- }
- ...
- }
从上述源码中,我们可以看到有一段if/else块,通过调用ProxyRequestHelper的addIgnoredHeaders方法来添加需要忽略的信息到请求上下文中,供后续ROUTE阶段的过滤器使用。这里的if/else块分别用来处理全局设置的敏感头信息和指定路由设置的敏感头信息。而全局的敏感头信息定义于ZuulProperties中:
- @Data
- @ConfigurationProperties("zuul")
- public class ZuulProperties{
- private Set<String> sensitiveHeaders = new LinkedHashSet<>(
- Arrays.asList("Cookie", "Set-Cookie", "Authorization"));
- ...
- }
所以解决该问题的思路也很简单,我们只需要通过设置sensitiveHeaders即可,设置方法分为两种:
1. 全局设置:
2. 指定路由设置:
- zuul.routes..sensitive-headers=
- zuul.routes..custom-sensitive-headers=true
二、重定向问题
在使用Spring Cloud Zuul对接Web网站的时候,处理完了会话控制问题之后。往往我们还会碰到如下图所示的问题,我们在浏览器中通过Zuul发起了登录请求,该请求会被路由到某WebSite服务,该服务在完成了登录处理之后,会进行重定向到某个主页或欢迎页面。此时,仔细的开发者会发现,在登录完成之后,我们浏览器中URL的HOST部分发生的改变,该地址变成了具体WebSite服务的地址了。这就是在这一节,我们将分析和解决的重定向问题!
出现该问题的根源是Spring Cloud Zuul没有正确的处理HTTP请求头信息中的Host导致。在Brixton版本中,Spring Cloud Zuul的PreDecorationFilter过滤器实现时完全没有考虑这一问题,它更多的定位于REST API的网关。所以如果要在Brixton版本中增加这一特性就相对较为复杂,不过好在Camden版本之后,Spring Cloud Netflix 1.2.x版本的Zuul增强了该功能,我们只需要通过配置属性zuul.add-host-header=true就能让原本有问题的重定向操作得到正确的处理。关于更多Host头信息的处理,读者可以参考本文之前的分析思路,可以通过查看PreDecorationFilter过滤器的源码来详细更多实现细节。
默认过滤的header
spring-cloud-netflix-core-1.2.6.RELEASE-sources.jar!/org/springframework/cloud/netflix/zuul/filters/ZuulProperties.java
/**
* List of sensitive headers that are not passed to downstream requests. Defaults to a
* "safe" set of headers that commonly contain user credentials. It
* those from the list if the downstream service is part of the same system as the
* proxy, so they are sharing authentication data. If using a physical URL outside
* your own domain, then generally it would be a bad idea to leak user credentials.
*/
private Set<String> sensitiveHeaders = new LinkedHashSet<>(
Arrays.asList("Cookie", "Set-Cookie", "Authorization"));
配置
zuul:
sensitiveHeaders:
host:
socket-timeout-millis: 60000
connect-timeout-millis: 60000
通过显示指定为空,表示让zuul的过滤header列表为空,这样就可以正常返回了
spring读取cookie方法
String xxx = WebUtils.getCookie((HttpServletRequest) servletRequest,"your-cookie-name").getValue();
http://zhuanlan.51cto.com/art/201705/538644.htm
相关推荐
Spring Cloud Gateway是新一代的API网关,它替代了Zuul,提供了更强大的路由规则、过滤器等功能,能够更灵活地处理请求和响应。 此外,Spring Cloud OpenFeign是声明式服务调用的组件,简化了服务之间的调用,使得...
springcloud入门代码基于Spring Cloud实现的服务网关Zuul源代码 安装教程 Zuul pom.xml <groupId>org.springframework.cloud <artifactId>spring-cloud-starter-netflix-zuul application.yml server:...
7. **Spring Cloud Gateway**:Spring Cloud的最新版本中,Zuul已被Gateway取代,Gateway提供更强大的路由功能和过滤器机制,能够处理更复杂的API管理和路由逻辑。 8. **Spring Cloud OpenFeign**:OpenFeign简化了...
Spring Cloud Zuul2 Zuul与Spring Cloud的集成。 警告:正在进行中入门启动zuul服务器./src/test/java/rocks/devmesh/spring/cloud/zuul/Application#main请求到'/ healthcheck'端点$ curl ...
4. 启动Zuul:将Zuul配置为一个独立的服务实例,或者将其与其他Spring Cloud服务(如Eureka)结合部署。 在提供的"zuulTest"文件名中,可能包含的是一个测试用例或样例代码,用于演示如何在实际项目中使用和测试...
《Spring Cloud实战教程》是一本全面且深入的指南,旨在帮助开发者从初识到精通Spring Cloud,从而在微服务架构领域建立起坚实的基础。Spring Cloud作为Java领域的热门框架,为构建分布式系统提供了丰富的工具集,...
8. **Spring Cloud Gateway**:在新版本的Spring Cloud中,Zuul被Spring Cloud Gateway取代,后者提供更强大的路由规则和过滤器。学习Gateway如何作为统一的入口,处理请求路由、熔断、限流等任务。 9. **Spring ...
本文将深入探讨Spring Cloud Zuul 的核心概念、功能和使用方法。 首先,Zuul 是 Netflix 开源的一款基于 JVM 的边缘服务框架,它为微服务提供了动态路由、过滤、安全控制等功能。在Spring Cloud生态中,Zuul 被广泛...
springcloud:Zuul动态网关demo源码案例演示
SpringCloud实战小贴士之Zuul的路径匹配 在SpringCloud实战小贴士之Zuul的路径匹配中,路由匹配是非常重要的一部分。 Zuul作为SpringCloud的网关组件,路径匹配是其核心功能之一。在本篇文章中,我们将详细介绍Zuul...
spring cloud 客户端和spring cloud zuul ,和前面的两个是一个系列,先打开cloud service 的服务,然后打开 product ,在打开客户端,最后可以打开zuul 可以实现eurake的负载均衡,zuul的负载均衡。
Spring Cloud Zuul:API网关服务详解 Spring Cloud Zuul 是 Spring Cloud Netflix 子项目的核心组件之一,可以作为微服务架构中的 API 网关使用,支持动态路由与过滤功能。API 网关为微服务架构中的服务提供了统一...
7. **SpringCloud Gateway**:相较于Zuul,SpringCloud Gateway是更现代的API Gateway,它基于Spring Framework 5、Project Reactor和Spring Boot 2,提供了更高效的性能和更丰富的路由策略。 8. **SpringCloud ...
Spring Cloud Zuul 是一个强大的边缘服务工具,作为微服务架构中的 API 网关,它在客户端和微服务之间起到了中介的作用。Zuul 主要包含两大核心功能:路由和过滤器。 1. 路由功能:Zuul 负责将来自外部的请求转发到...
在这个例子中,我们主要关注的是 Zuul,它是Spring Cloud的一个边缘服务和动态路由组件,用作API网关。 Zuul的主要职责包括: 1. **动态路由**:Zuul可以对请求进行路由,将客户端的请求转发到不同的后端服务。...
4. **Spring Cloud Zuul**:Zuul是边缘服务和动态路由组件,可以作为API网关,处理所有微服务的入口请求,实现路由转发、过滤器操作以及安全控制等功能。 5. **Spring Cloud Config**:提供了一种集中式管理应用...
spring-cloud-netflix-zuul-websocket, Zuul反向代理网络套接字支持 spring-cloud-netflix-zuul-websocketspring 应用程序中支持Zuul反向代理web套接字支持的简单库。用法spring-cloud-netflix-zuul-websocket可以从...
- **Spring Cloud Gateway**:新一代的API网关,替代Zuul,提供了更丰富的路由规则和过滤器支持。 - **Spring Cloud Sleuth**:用于追踪链路,支持Zipkin、Jaeger等多种追踪系统集成。 - **Spring Cloud Stream**:...
在本文中,我们将探讨 Spring Cloud 网关 Zuul 和负载均衡 Ribbon 的应用。 Zuul 网关 Zuul 是 Netflix 公司开源的一种基于 JVM 的网关组件,负责处理外部请求并将其路由到正确的微服务实例上。 Zuul 提供了多种...
4. **安全控制**:除了认证外,Zuul还支持安全相关的功能,如IP黑白名单、请求参数校验等,可以在请求到达服务之前进行拦截和处理,防止非法或恶意请求对系统造成影响。 5. **负载均衡**:作为微服务架构的一部分,...