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=301 和 requestRedirect.scheme="https":
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:
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:
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: 308POST-Redirect-GET 模式
要实现 POST-Redirect-GET 模式,使用状态码 303,把 POST 请求重定向到 GET 端点:
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: 303HTTP → HTTPS 重定向
要把 HTTP 流量重定向到 HTTPS,你的 Gateway 需要同时拥有 HTTP 和 HTTPS 两个 listener。
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。
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 流量转发到应用后端:
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):
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 改成下面这样:
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/pinch 和 location: https://redirect.example/paprika/teaspoon 这样的响应头。
改写(Rewrites)
改写会在代理请求到上游之前,修改客户端请求中的某些部分。URLRewrite filter 可以改写上游请求的 hostname 和/或 path。举例来说,下面的 HTTPRoute 会接收一个对 https://rewrite.example/cardamom 的请求,然后把请求代理到 example-svc 上游,且请求头中的 host 字段是 elsewhere.example 而不是 rewrite.example:
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 上游:
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: ReplacePrefixMatch 加 replacePrefixMatch: /fennel 则会使上游请求变为 https://elsewhere.example/fennel/smidgen:
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