You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Cloud Gateway:基于请求头重定向及代理静态资源异常问题

解决Spring Cloud Gateway代理Google时静态资源加载异常的问题

这个问题我之前碰到过类似的,核心原因是页面里的静态资源引用路径没有和代理路径同步,导致浏览器要么直接请求原域名(跨域或网络问题),要么请求你的服务器未代理的路径(404)。下面给你分析原因和具体的解决方案:

问题根源拆解

当你用ProxyExchange代理https://www.google.com后,返回的页面里的资源引用通常有两种情况:

  • 绝对路径:比如<img src="https://www.google.com/images/logo.png">,浏览器会直接请求Google的域名,可能因为跨域限制、网络防火墙等原因加载失败;
  • 根相对路径:比如<img src="/images/logo.png">,浏览器会基于当前页面的URL(比如https://your-domain/proxgoo/)去请求https://your-domain/images/logo.png,而这个路径并没有被你的代理逻辑覆盖,所以返回404。

解决方案一:改用Spring Cloud Gateway内置路由配置(推荐)

Spring Cloud Gateway自带了专门的过滤器来处理代理场景的路径重写、响应体修改,比手动用ProxyExchange更健壮。用Kotlin配置路由的示例如下:

import org.springframework.cloud.gateway.route.RouteLocator
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder
import org.springframework.cloud.gateway.filter.factory.RewriteLocationResponseHeaderFilter
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration

@Configuration
class GatewayConfig {
    @Bean
    fun customRouteLocator(builder: RouteLocatorBuilder): RouteLocator {
        return builder.routes()
            .route("google-proxy") { r ->
                r.path("/proxgoo/**")
                    .filters { f ->
                        // 把/proxgoo/xxx重写为/xxx转发给Google
                        f.rewritePath("/proxgoo/(?<segment>.*)", "/${'$'}segment")
                        // 重写Location响应头,处理Google的重定向路径
                        .rewriteLocationResponseHeader(
                            RewriteLocationResponseHeaderFilter.LocationRewriteMode.AS_IN_REQUEST,
                            "Location", "", "/proxgoo/"
                        )
                        // 修改响应体里的所有根相对路径,加上/proxgoo前缀
                        .modifyResponseBody<String, String> { _, body ->
                            body.replace("""src="/""", """src="/proxgoo/""")
                                .replace("""href="/""", """href="/proxgoo/""")
                                .replace("""action="/""", """action="/proxgoo/""")
                        }
                    }
                    .uri("https://www.google.com")
            }
            .build()
    }
}

这个配置会自动处理:

  1. 路径转发:把/proxgoo/xxx转发到https://www.google.com/xxx;
  2. 重定向修正:如果Google返回重定向,自动把Location里的路径加上/proxgoo前缀;
  3. 静态资源路径替换:把页面里的所有根相对资源引用都改成代理路径,确保浏览器走你的代理请求资源。

解决方案二:手动修改ProxyExchange的响应(适合简单场景)

如果你坚持要用原来的ProxyExchange方式,需要手动修改响应体和响应头,把资源路径调整为代理路径:

import org.springframework.http.HttpHeaders
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RestController
import org.springframework.web.servlet.mvc.method.annotation.ProxyExchange
import java.net.URI

@RestController
class ProxyController {
    private val proxiedRemote = URI.create("https://www.google.com")

    @GetMapping("/proxgoo/**")
    fun proxyPath(proxy: ProxyExchange<*>): ResponseEntity<*> {
        val path = proxy.path("/proxgoo/")
        val originalResponse = proxy.uri("${proxiedRemote}/$path").get()

        // 1. 修改响应体里的资源路径
        val modifiedBody = (originalResponse.body as? String)?.run {
            replace("""src="/""", """src="/proxgoo/""")
                .replace("""href="/""", """href="/proxgoo/""")
                .replace("""action="/""", """action="/proxgoo/""")
                // 额外处理绝对URL的情况,替换成代理路径
                .replace(proxiedRemote.toString(), "/proxgoo")
        } ?: originalResponse.body

        // 2. 修改Location响应头,处理重定向
        val modifiedHeaders = HttpHeaders(originalResponse.headers).apply {
            location?.let { location ->
                when {
                    location.path.startsWith("/") -> {
                        this.location = URI.create("/proxgoo${location.path}${location.query?.let { "?$it" } ?: ""}")
                    }
                    location.host == proxiedRemote.host -> {
                        this.location = URI.create("/proxgoo${location.path}${location.query?.let { "?$it" } ?: ""}")
                    }
                }
            }
        }

        return ResponseEntity.status(originalResponse.statusCode)
            .headers(modifiedHeaders)
            .body(modifiedBody)
    }
}

额外注意事项

  • Google的页面有很多动态加载的资源(比如JS动态生成的路径),上面的字符串替换可能无法覆盖所有情况,这种场景下推荐用Gateway的路由配置,或者考虑使用专门的HTML解析库(比如Jsoup)来更精准地修改资源路径;
  • 如果遇到跨域问题,可以在Gateway里添加CORS过滤器,允许浏览器访问代理后的资源;
  • 部分资源可能有Referer校验,需要在代理时传递正确的Referer头,Gateway的过滤器会自动处理这一点。

内容的提问来源于stack exchange,提问作者user5539487

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 09:47:42