如何在 kubernetes 上的 nginx 控制器中将 URL 重写为小写

How to rewrite URLs to lowercase in nginx controller on kubernetes

我有一个要求将所有 URL 重写为小写。

例如test.com/CHILDtest.com/child

前端应用程序是在 docker Azure kubernetes 服务上开发的。入口由 nginx 入口控制器控制。

入口控制器在 spec.rules.http.paths.path 字段中支持 不区分大小写 正则表达式。这可以通过将 nginx.ingress.kubernetes.io/use-regex 注释设置为 true(默认为 false)来启用。有关更多信息,请查看 here

使用 nginx.ingress.kubernetes.io/use-regex 注释将指示 Ingress 上定义的路径是否使用正则表达式。默认值为 false。

以下将表明正在使用正则表达式路径:

nginx.ingress.kubernetes.io/use-regex: "true"

以下将指示未使用正则表达式路径:

nginx.ingress.kubernetes.io/use-regex: "false"

当此注释设置为 true 时,不区分大小写的正则表达式 location modifier 将在给定主机的所有路径上强制执行,无论它们是在哪个 Ingress 上定义的。

[Reference]

您可以使用 Lua 重写 URL,如 Enforce Lower Case URLs (NGINX) 文章中所述。

我们需要做的就是在nginx中添加如下配置块:

location ~ [A-Z] {
    rewrite_by_lua_block {
        ngx.redirect(string.lower(ngx.var.uri), 301);
    }
}

我会告诉你它是如何工作的。


首先,我使用前面提到的配置创建了一个 Ingress 资源:

$ cat test-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: test-ingress
  annotations:
    kubernetes.io/ingress.class: nginx
    nginx.ingress.kubernetes.io/rewrite-target: /
    nginx.ingress.kubernetes.io/server-snippet: |
     location ~ [A-Z] {
        rewrite_by_lua_block {
            ngx.redirect(string.lower(ngx.var.uri), 301);
        }
      }
spec:
  rules:
  - http:
      paths:
      - path: /app-1
        pathType: Prefix
        backend:
          service:
            name: app-1
            port:
              number: 80
              
              
$ kubectl apply -f test-ingress.yaml
ingress.networking.k8s.io/test-ingress created

$ kubectl get ing
NAME           CLASS    HOSTS   ADDRESS          PORTS   AGE
test-ingress   <none>   *       <PUBLIC_IP>      80      58s

然后我创建了一个示例 app-1 Pod 并将其暴露在端口 80:

$ kubectl run app-1 --image=nginx
pod/app-1 created

$ kubectl expose pod app-1 --port=80
service/app-1 exposed

最后,我们可以测试重写是否按预期工作:

$ curl -I <PUBLIC_IP>/APP-1
HTTP/1.1 301 Moved Permanently
Date: Wed, 06 Oct 2021 13:53:56 GMT
Content-Type: text/html
Content-Length: 162
Connection: keep-alive
Location: /app-1

$ curl -L <PUBLIC_IP>/APP-1
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
...

此外,在 ingress-nginx-controller 日志中,我们可以看到以下日志条目:

10.128.15.213 - - [06/Oct/2021:13:54:34 +0000] "GET /APP-1 HTTP/1.1" 301 162 "-" "curl/7.64.0" 83 0.000 [-] [] - - - - c4720e38c06137424f7b951e06c3762b
10.128.15.213 - - [06/Oct/2021:13:54:34 +0000] "GET /app-1 HTTP/1.1" 200 615 "-" "curl/7.64.0" 83 0.001 [default-app-1-80] [] 10.4.1.13:80 615 0.001 200 f96b5664765035de8832abebefcabccf

解决方案的想法是好的,但这会重写这个控制器的所有 url,而不仅仅是这个入口的 url。将它放入 configuration-snippet 也是不可能的,因为这会导致重复 rewrite_by_lua_block。 我将规则放入不同的 lua 块

nginx.ingress.kubernetes.io/configuration-snippet: |
  access_by_lua_block {
    if string.match(ngx.var.uri, "[A-Z]") then
      ngx.redirect(string.lower(ngx.var.uri), 301);
    end
  }