Vue-router结合Ingress-Nginx重载页面出现404问题求助
问题背景
我有一个包含3个菜单的Vue.js单页应用,通过vue-router将URL从/切换为/users、/groups、/teams。但在这些页面按下Ctrl+R重载时会出现404错误。
当前配置
原始Ingress配置如下:
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: annotations: kubernetes.io/ingress.class: nginx nginx.ingress.kubernetes.io/auth-signin: https://$host/oauth2/start?rd=$escaped_request_uri nginx.ingress.kubernetes.io/auth-url: https://$host/oauth2/auth name: my-ing-oauth2-proxy spec: ingressClassName: nginx rules: - host: myhost.com http: paths: - backend: service: name: myservice port: number: 8080 path: / pathType: Prefix
该配置在访问/users等路径重载时会返回404。
已尝试方案
试过rewrite-target、app-root、use-regex等注解,试图将所有路由重定向到/,但均失败,出现白屏或404。
临时方案及问题
创建了第二个Ingress处理上述路由并重定向到/,但存在以下问题:
- 需要维护多个Ingress(还使用了oauth2-proxy);
- 必须硬编码路径,无法匹配所有路由(使用
/.+正则也无效)。
第二个Ingress配置如下:
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: annotations: nginx.ingress.kubernetes.io/auth-signin: https://$host/oauth2/start?rd=$escaped_request_uri nginx.ingress.kubernetes.io/auth-url: https://$host/oauth2/auth nginx.ingress.kubernetes.io/permanent-redirect: https://myhost.com # <= here nginx.ingress.kubernetes.io/use-regex: "true" name: my-ing-oauth2-proxy-routes spec: ingressClassName: nginx rules: - host: myhost.com http: paths: - backend: service: name: myservice port: number: 8080 path: /groups pathType: Prefix - backend: service: name: myservice port: number: 8080 path: /teams pathType: Prefix - backend: service: name: myservice port: number: 8080 path: /users pathType: Prefix
需求
希望通过单个Ingress将所有路由(/*)重定向到/;若无法实现,至少让第二个Ingress匹配所有路由而非硬编码。
环境
- nginx:2.4.1
- ingress-nginx helm chart:nginx-ingress-0.15.1
- Kubernetes:1.24.3
解决方案
方案1:单个Ingress实现Vue History模式路由(推荐)
Vue单页应用的history模式需要Ingress在请求路径找不到对应静态资源时,返回index.html,由vue-router接管路由。通过添加configuration-snippet注解实现这一逻辑,同时保留oauth2-proxy的认证配置:
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: annotations: kubernetes.io/ingress.class: nginx nginx.ingress.kubernetes.io/auth-signin: https://$host/oauth2/start?rd=$escaped_request_uri nginx.ingress.kubernetes.io/auth-url: https://$host/oauth2/auth nginx.ingress.kubernetes.io/configuration-snippet: | try_files $uri $uri/ /index.html; name: my-ing-oauth2-proxy spec: ingressClassName: nginx rules: - host: myhost.com http: paths: - backend: service: name: myservice port: number: 8080 path: / pathType: Prefix
原理:try_files指令会先尝试访问请求的路径(静态资源如JS/CSS/图片),如果找不到则返回index.html,vue-router就能正确解析URL中的路由参数,重载页面不再出现404,同时URL保持不变,用户体验更好。
方案2:单个Ingress重写所有路由到根路径
如果确实需要将所有路径重写到/(会改变URL),可以结合正则匹配和重写注解:
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: annotations: kubernetes.io/ingress.class: nginx nginx.ingress.kubernetes.io/auth-signin: https://$host/oauth2/start?rd=$escaped_request_uri nginx.ingress.kubernetes.io/auth-url: https://$host/oauth2/auth nginx.ingress.kubernetes.io/use-regex: "true" nginx.ingress.kubernetes.io/rewrite-target: / name: my-ing-oauth2-proxy spec: ingressClassName: nginx rules: - host: myhost.com http: paths: - backend: service: name: myservice port: number: 8080 path: /(.*) pathType: ImplementationSpecific
方案3:让第二个Ingress匹配所有路由
如果必须保留双Ingress结构,修改第二个Ingress的路径规则,用正则匹配所有非根路径:
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: annotations: nginx.ingress.kubernetes.io/auth-signin: https://$host/oauth2/start?rd=$escaped_request_uri nginx.ingress.kubernetes.io/auth-url: https://$host/oauth2/auth nginx.ingress.kubernetes.io/permanent-redirect: https://myhost.com nginx.ingress.kubernetes.io/use-regex: "true" name: my-ing-oauth2-proxy-routes spec: ingressClassName: nginx rules: - host: myhost.com http: paths: - backend: service: name: myservice port: number: 8080 path: /(.*) pathType: ImplementationSpecific
注意:需要确保第一个Ingress的path: /优先级低于第二个Ingress的正则路径(Ingress会按最长匹配优先,但正则匹配需配合ImplementationSpecific路径类型)。
内容的提问来源于stack exchange,提问作者Doctor

