如何通过Nginx Ingress基于路径路由为服务提供静态文件?
解决前端服务部署在Nginx Ingress子路径下的静态资源路径问题
针对前端服务部署在example.com/front1这类子路径下,静态资源用绝对根路径(如href="/styles.css")导致404的问题,以下是几种无需修改前端源码的可行方案:
方案1:利用NJS动态改写请求路径(推荐)
这个方案通过Nginx的NJS模块,根据请求的Referer头判断请求所属的子服务,自动将根路径资源请求重写到对应子路径下,能覆盖动态JS生成的请求。
配置步骤:
创建NJS脚本ConfigMap
apiVersion: v1 kind: ConfigMap metadata: name: nginx-njs-scripts namespace: ingress-nginx data: path_rewrite.js: | function getBasePath(r) { const referer = r.headersIn['Referer']; if (!referer) return ''; // 从Referer中提取子路径前缀(如从http://example.com/front1/page提取/front1) const url = new URL(referer); const pathSegments = url.pathname.split('/'); if (pathSegments.length >= 2 && pathSegments[1]) { return '/' + pathSegments[1]; } return ''; }修改Ingress Controller Deployment挂载ConfigMap
找到Ingress Controller的Deployment(通常在ingress-nginx命名空间),添加Volume和VolumeMount:spec: template: spec: volumes: - name: njs-scripts configMap: name: nginx-njs-scripts containers: - name: controller volumeMounts: - name: njs-scripts mountPath: /etc/nginx/conf.d/ readOnly: true在目标服务的Ingress中注入Server Snippet
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: front1-ingress annotations: nginx.ingress.kubernetes.io/rewrite-target: /$1 nginx.ingress.kubernetes.io/server-snippet: | js_import /etc/nginx/conf.d/path_rewrite.js; js_set $base_path path_rewrite.getBasePath; # 仅对根路径开头的请求进行改写,避免影响子路径下的正常请求 if ($base_path != '' && $request_uri ~ ^/[^/]+) { rewrite ^/(.*)$ $base_path/$1 break; } spec: rules: - host: example.com http: paths: - path: /front1/?(.*) pathType: Prefix backend: service: name: front1-service port: number: 80
优缺点:
- 优点:无需修改响应体,能处理动态JS生成的资源请求,适配所有第三方前端服务
- 缺点:依赖
Referer头,若用户直接访问根路径资源URL(如example.com/styles.css)会失效,但这类场景极少
方案2:基于Referer的Nginx条件重写(轻量版)
如果不想折腾NJS,可以直接用Nginx的原生指令实现类似逻辑,配置更简单:
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: front1-ingress annotations: nginx.ingress.kubernetes.io/rewrite-target: /$1 nginx.ingress.kubernetes.io/server-snippet: | # 匹配Referer中的子路径前缀,并重写请求路径 if ($http_referer ~* "^https?://example.com/([^/]+)/") { set $service_prefix /$1; rewrite ^/(.*)$ $service_prefix/$1 last; } spec: rules: - host: example.com http: paths: - path: /front1/?(.*) pathType: Prefix backend: service: name: front1-service port: number: 80
优缺点:
- 优点:无需额外挂载脚本,配置快速
- 缺点:正则匹配能力有限,不适用于多层子路径的场景
方案3:Proxy Redirect结合Sub Filter(适配静态页面)
如果服务以静态页面为主,动态生成内容较少,可以结合proxy_redirect和sub_filter注解,同时修改响应头和响应体中的绝对路径:
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: front1-ingress annotations: nginx.ingress.kubernetes.io/rewrite-target: /$1 nginx.ingress.kubernetes.io/proxy-redirect: "http://example.com/ http://example.com/front1/" nginx.ingress.kubernetes.io/proxy-redirect: "https://example.com/ https://example.com/front1/" nginx.ingress.kubernetes.io/configuration-snippet: | sub_filter 'href="/' 'href="/front1/'; sub_filter 'src="/' 'src="/front1/'; sub_filter_once off; spec: rules: - host: example.com http: paths: - path: /front1/?(.*) pathType: Prefix backend: service: name: front1-service port: number: 80
优缺点:
- 优点:能覆盖静态页面中的所有绝对路径引用
- 缺点:对动态JS生成的路径无效,因为Sub Filter只处理初始响应体
方案4:兜底精确路径代理
如果上述方案都无法满足,且服务的静态资源路径固定,可以为每个资源单独配置Ingress规则:
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: front1-resources-ingress spec: rules: - host: example.com http: paths: - path: /styles.css pathType: Exact backend: service: name: front1-service port: number: 80 - path: /app.js pathType: Exact backend: service: name: front1-service port: number: 80 # 继续添加其他静态资源路径
优缺点:
- 优点:配置简单,无需复杂逻辑
- 缺点:需要维护大量精确路径规则,仅适用于资源数量少的服务
内容的提问来源于stack exchange,提问作者Emanuel Kozerski
相关产品推荐
相关产品推荐

