GCP App Engine柔性环境部署Spring Cloud Gateway出现302无限重定向循环
问题背景
在GCP App Engine中运行两个服务(记为服务A、服务B),后续部署Spring Cloud Gateway服务,基于path predicates将外部流量路由至这两个服务。服务A、B均部署在App Engine flexible环境,最初网关部署在App Engine standard环境时运行完全正常;由于部分批处理服务响应时长超过10分钟(App Engine standard环境最大响应超时为10分钟),因此将网关迁移至App Engine flexible环境。
网关服务已完成Docker容器化封装,运行在8080端口,使用的app.yaml配置如下:
runtime: custom env: flex service: beta-gateway env_variables: SPRING_PROFILES_ACTIVE: "beta" resources: cpu: 1 memory_gb: 2 liveness_check: path: "/actuator/health" check_interval_sec: 30 timeout_sec: 4 failure_threshold: 2 success_threshold: 2 initial_delay_sec: 300 readiness_check: path: "/actuator/health" check_interval_sec: 5 timeout_sec: 4 failure_threshold: 2 success_threshold: 2 app_start_timeout_sec: 300
服务可正常部署,actuator端点运行完全正常,调用/actuator/gateway/routes端点查看,路由配置无误(当前通过appspot DNS URI将请求路由至服务A、B,该方案并非最优,后续计划替换为服务注册中心实现)。
故障现象
除actuator端点外,访问其余任意端点时请求都会进入302重定向循环,最终调用失败。
已完成排查操作
- 调用
/actuator/gateway/routes端点确认路由配置正常 - 为网关开启TRACE级别日志,观测到路由可正确匹配到服务A或B对应的appspot DNS URL
存疑配置
最初部署时曾在network配置中指定端口绑定,配置如下,后续了解到8080端口为默认绑定端口,因此移除了该段配置,不确定该配置是否与故障相关:
network: name: default forwarded_ports: - 80:8080
根因分析与解决方案
核心根因
App Engine Flex公网前端默认开启HTTP强制跳转HTTPS策略,当前网关转发请求到后端服务的appspot地址时使用的是HTTP协议,App Engine前端收到HTTP请求会返回302响应要求跳转到HTTPS地址;而Spring Cloud Gateway默认不会自动跟随跨域重写协议,收到302后会继续按原HTTP逻辑转发请求,反复触发强制跳转,最终形成重定向循环。
actuator端点直接在网关本地处理,不需要转发到后端服务,因此不会触发该问题。
之前移除的forwarded_ports配置和该故障无关,8080确实是App Engine Flex自定义运行时的默认监听端口,不需要额外配置端口映射。
排查&修复步骤
- 先验证根因:抓取任意失败请求的响应报文,查看302响应的
Location头,如果值为对应后端服务的HTTPS协议地址,即可确认是协议不匹配导致的循环。 - 修改网关路由配置,将所有转发到后端appspot地址的URI从HTTP协议改为HTTPS协议,例如将
uri: http://service-a.xxx.appspot.com修改为uri: https://service-a.xxx.appspot.com。 - 补充网关转发头配置,避免后端服务识别错请求协议导致二次跳转,在Spring配置中添加如下参数:
spring: cloud: gateway: forward-headers-strategy: framework httpclient: ssl: use-insecure-trust-manager: false - 配置修改完成后重新部署网关版本,部署时建议生成新版本做流量切分验证,不要直接覆盖原有版本:
部署完成后先直接访问新版本地址验证转发逻辑,确认无循环后再将流量切到新版本。gcloud app deploy app.yaml --version gw-fix-https --no-promote
后续优化建议
当前通过公网appspot域名做服务间调用的方案额外增加了公网链路开销,后续替换服务注册中心时,可以直接使用App Engine内置的内网服务域名http://[你的服务名].apps.internal做服务间调用,走内网链路不需要经过公网前端,既不会触发HTTPS强制跳转,也能降低调用延迟。
内容的提问来源于stack exchange,提问作者Praveen Dass

