Istio VirtualService路径重写导致页面资源URL失效问题求助
这个问题很典型——你把客户端请求的/drill/前缀重写成了后端的/,但后端返回的HTML里所有资源和链接都是基于根路径/的,浏览器会直接请求https://<HOST>/storage而不是https://<HOST>/drill/storage,自然就找不到资源了。下面给你几个可行的解决思路:
方案1:修改Drill服务的上下文路径(推荐)
最彻底的办法是让Drill本身知道它运行在/drill这个上下文路径下,这样它生成的HTML链接会自动带上/drill前缀。Drill的Web控制台支持通过配置设置上下文路径,你可以在Drill的配置文件(比如drill-override.conf)里添加:
drill.exec.http.web.root: "/drill"
修改后重启Drill服务,然后调整你的VirtualService,去掉rewrite规则:
http: - match: - uri: prefix: /drill/ route: - destination: host: drill-service.drill.svc.cluster.local port: number: 8047
这样客户端请求/drill/storage时,后端直接处理这个路径,页面里的链接也会是/drill/storage,完美匹配。
方案2:用Istio EnvoyFilter改写响应内容(不改应用的情况下)
如果没法修改Drill的配置,那可以通过Istio的EnvoyFilter来拦截响应,把HTML里的根路径链接替换成带/drill前缀的。创建一个EnvoyFilter资源:
apiVersion: networking.istio.io/v1alpha3 kind: EnvoyFilter metadata: name: drill-response-rewrite namespace: istio-system # 或者你的服务所在namespace spec: workloadSelector: labels: istio: ingressgateway # 针对入口网关 configPatches: - applyTo: HTTP_FILTER match: context: GATEWAY listener: filterChain: filter: name: "envoy.filters.network.http_connection_manager" subFilter: name: "envoy.filters.http.router" patch: operation: INSERT_BEFORE value: name: envoy.filters.http.lua typed_config: "@type": "type.googleapis.com/udpa.type.v1.TypedStruct" type_url: "type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua" value: inline_code: | function envoy_on_response(response_handle) local body = response_handle:body() if body then local modified_body = string.gsub(body:getBytes(0, body:length()), 'href="/', 'href="/drill/') modified_body = string.gsub(modified_body, 'src="/', 'src="/drill/') response_handle:body():setBytes(modified_body) end end
这个Lua脚本会把响应里所有href="/和src="/的内容替换成href="/drill/和src="/drill/,这样浏览器就会请求正确的路径了。注意这个方案只适合HTML文本内容,如果有其他类型的响应可能需要调整脚本。
方案3:保留rewrite,但配置浏览器端的base标签
另一个思路是在HTML页面里添加<base href="/drill/">标签,这样所有相对路径都会基于这个base路径。你可以通过Istio的EnvoyFilter在响应的<head>里插入这个标签,或者如果能修改Drill的模板页面的话直接添加。不过这个方案不如前两个可靠,因为有些页面可能没有<head>标签,或者资源路径是绝对路径的话还是会有问题。
总结一下,优先推荐方案1,因为它从根源上解决了路径问题,方案2作为无法修改应用时的替代方案。
内容的提问来源于stack exchange,提问作者MBR

