Skip to content

HTTP 路径重定向与改写

原文:https://gateway-api.sigs.k8s.io/guides/user-guides/http-redirect-rewrite/

HTTPRoute 资源 可以对客户端发起重定向,也可以改写发往后端的路径,方法是使用 filters。本指南展示如何使用这些功能。

注意:重定向 filter 和改写 filter 互不兼容。同一条规则不能同时使用这两类 filter。

重定向(Redirects)

重定向返回一个 HTTP 3XX 响应给客户端,要求它获取另一个资源。RequestRedirect 规则 filter 指示 Gateway 对匹配过滤后 HTTPRoute 规则的请求发出重定向响应。

支持的状态码

Gateway API 支持以下 HTTP 重定向状态码:

  • 301(Moved Permanently):表示资源已永久地移到了新位置。搜索引擎和客户端会更新自己的引用,改用新 URL。适用于像"HTTP → HTTPS 升级"或"URL 永久变更"这样的永久重定向。
  • 302(Found):表示资源临时位于另一个位置。如果不显式指定状态码,这就是默认状态码。适用于"原 URL 将来可能再次有效"的临时重定向。
  • 303(See Other):表示该请求的响应可以在另一个 URL 上通过 GET 方法取得。它用于在 POST 请求之后重定向到确认页,从而避免重复提交表单。
  • 307(Temporary Redirect):与 302 类似,但保证在跟随重定向时不会改变 HTTP 方法。当需要在重定向中保留原始 HTTP 方法(POST、PUT 等)时,它。
  • 308(Permanent Redirect):与 301 类似,但保证在跟随重定向时不会改变 HTTP 方法。适用于"必须保留 HTTP 方法"的永久重定向。

重定向 filter 可以独立地替换 URL 中的各个组成部分。举例来说,要从 HTTP 永久重定向(301)到 HTTPS,只需配置 requestRedirect.statusCode=301requestRedirect.scheme="https"

yaml
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: http-filter-redirect
spec:
  parentRefs:
  - name: redirect-gateway
    sectionName: http
  hostnames:
  - redirect.example
  rules:
  - filters:
    - type: RequestRedirect
      requestRedirect:
        scheme: https
        statusCode: 301

重定向会按配置修改 URL 中的指定部分,其余部分则保留自原始请求 URL。在本例中,请求 GET http://redirect.example/cinnamon 将得到一个 301 响应,响应头包含 location: https://redirect.example/cinnamon主机名redirect.example)、路径/cinnamon)和端口(隐式)都保持不变

保留方法的重定向

当你需要保证重定向过程中 HTTP 方法不变时,使用 307 或 308:

yaml
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: method-preserving-redirect
spec:
  parentRefs:
  - name: redirect-gateway
  hostnames:
  - api.example.com
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /api/v1
    filters:
    - type: RequestRedirect
      requestRedirect:
        path:
          type: ReplaceFullPath
          replaceFullPath: /api/v2
        statusCode: 307

对于必须保留 HTTP 方法的永久重定向,使用 308:

yaml
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: permanent-method-preserving-redirect
spec:
  parentRefs:
  - name: redirect-gateway
  hostnames:
  - api.example.com
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /old-api
    filters:
    - type: RequestRedirect
      requestRedirect:
        path:
          type: ReplaceFullPath
          replaceFullPath: /new-api
        statusCode: 308

POST-Redirect-GET 模式

要实现 POST-Redirect-GET 模式,使用状态码 303,把 POST 请求重定向到 GET 端点:

yaml
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: post-redirect-get
spec:
  parentRefs:
  - name: redirect-gateway
  hostnames:
  - forms.example.com
  rules:
  - matches:
    - path:
        type: Exact
        value: /submit-form
      method: POST
    filters:
    - type: RequestRedirect
      requestRedirect:
        path:
          type: ReplaceFullPath
          replaceFullPath: /thank-you
        statusCode: 303

HTTP → HTTPS 重定向

要把 HTTP 流量重定向到 HTTPS,的 Gateway 需要同时拥有 HTTP 和 HTTPS 两个 listener。

yaml
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: redirect-gateway
spec:
  gatewayClassName: foo-lb
  listeners:
  - name: http
    protocol: HTTP
    port: 80
  - name: https
    protocol: HTTPS
    port: 443
    tls:
      mode: Terminate
      certificateRefs:
      - name: redirect-example

保障 Gateway 安全的方式有多种。本例中,它是通过 Kubernetes Secret(certificateRefs 段中的 redirect-example)来保障的。

需要一条挂到 HTTP listener、并执行 HTTPS 重定向的 HTTPRoute。这里sectionName 设为 http,使它选中名为 http 的那个 listener。

yaml
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: http-filter-redirect
spec:
  parentRefs:
  - name: redirect-gateway
    sectionName: http
  hostnames:
  - redirect.example
  rules:
  - filters:
    - type: RequestRedirect
      requestRedirect:
        scheme: https
        statusCode: 301

还需要另一条挂到 HTTPS listener 的 HTTPRoute,负责把 HTTPS 流量转发到应用后端:

yaml
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: https-route
  labels:
    gateway: redirect-gateway
spec:
  parentRefs:
  - name: redirect-gateway
    sectionName: https
  hostnames:
  - redirect.example
  rules:
  - backendRefs:
    - name: example-svc
      port: 80

路径重定向

路径重定向使用 HTTP Path Modifier,可以替换整个路径或路径前缀。举例来说,下面的 HTTPRoute 会对所有 redirect.example 主机名下、路径 /cayenne 开头的请求,发出一个 302 重定向到 /paprika。注意你可以根据需要任选支持的状态码(301, 302, 303, 307, 308):

yaml
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: http-filter-redirect
spec:
  hostnames:
    - redirect.example
  rules:
    - matches:
        - path:
            type: PathPrefix
            value: /cayenne
      filters:
        - type: RequestRedirect
          requestRedirect:
            path:
              type: ReplaceFullPath
              replaceFullPath: /paprika
            statusCode: 302

https://redirect.example/cayenne/pinch

https://redirect.example/cayenne/teaspoon

两个请求,都会得到 location: https://redirect.example/paprika 这样的重定向响应。

另一类路径重定向 ReplacePrefixMatch替换 matches.path.value 相匹配的那部分路径。把上面例子的 filter 成下面这样:

yaml
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: http-filter-redirect
spec:
  hostnames:
    - redirect.example
  rules:
    - matches:
        - path:
            type: PathPrefix
            value: /cayenne
      filters:
        - type: RequestRedirect
          requestRedirect:
            path:
              type: ReplacePrefixMatch
              replacePrefixMatch: /paprika
            statusCode: 302

结果会得到 location: https://redirect.example/paprika/pinchlocation: https://redirect.example/paprika/teaspoon 这样的响应头。

改写(Rewrites)

改写会在代理请求到上游之前,修改客户端请求中的某些部分。URLRewrite filter 可以改写上游请求的 hostname 和/或 path。举例来说,下面的 HTTPRoute 会接收一个对 https://rewrite.example/cardamom 的请求,然后把请求代理example-svc 上游,且请求头中的 host 字段 elsewhere.example 而不是 rewrite.example

yaml
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: http-filter-rewrite
spec:
  hostnames:
    - rewrite.example
  rules:
    - filters:
        - type: URLRewrite
          urlRewrite:
            hostname: elsewhere.example
      backendRefs:
        - name: example-svc
          weight: 1
          port: 80

路径改写是使用 HTTP Path Modifier。下面的 HTTPRoute 会接收https://rewrite.example/cardamom/smidgen 的请求,然后把对 https://elsewhere.example/fennel 的请求代理example-svc 上游:

yaml
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: http-filter-rewrite
spec:
  hostnames:
    - rewrite.example
  rules:
    - matches:
        - path:
            type: PathPrefix
            value: /cardamom
      filters:
        - type: URLRewrite
          urlRewrite:
            hostname: elsewhere.example
            path:
              type: ReplaceFullPath
              replaceFullPath: /fennel
      backendRefs:
        - name: example-svc
          weight: 1
          port: 80

而改用 type: ReplacePrefixMatchreplacePrefixMatch: /fennel 则会使上游请求变为 https://elsewhere.example/fennel/smidgen

yaml
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: http-filter-rewrite
spec:
  hostnames:
    - rewrite.example
  rules:
    - matches:
        - path:
            type: PathPrefix
            value: /cardamom
      filters:
        - type: URLRewrite
          urlRewrite:
            hostname: elsewhere.example
            path:
              type: ReplacePrefixMatch
              replacePrefixMatch: /fennel
      backendRefs:
        - name: example-svc
          weight: 1
          port: 80

基于 MIT 协议发布