请求转换包括请求路径、查询、HTTP 版本、方法和标头。 在代码中,这些对象由 RequestTransformContext 对象表示,并由抽象类 RequestTransform 的实现处理。
注释:
- 代理请求方案 (http/https)、颁发机构和路径库取自目标服务器地址(上面的示例中为
https://localhost:10001/Path/Base
),不应通过转换进行修改。 - 主机标头可以通过不依赖于授权的转换来替代,请参阅下面的 RequestHeader。
- 构造代理请求时,不会使用请求的原始 PathBase 属性,请参阅 X 转发。
- 默认情况下,所有传入的请求标头都会复制到代理请求,但主机标头除外(请参阅
Defaults
默认值)。 默认情况下还会添加 X-Forwarded 标头。 这些行为可以使用以下转换进行配置。 可以指定其他请求标头,也可以通过将请求标头设置为空值来排除请求标头。
以下是通过其主要配置键识别的内置转换。 这些转换按路由配置中指定的顺序应用。
PathPrefix
修改添加前缀值的请求路径
密钥 | 价值 | 必选 |
---|---|---|
PathPrefix | 以“/”开头的路径 | 是的 |
Config:
{ "PathPrefix": "/prefix" }
代码:
routeConfig = routeConfig.WithTransformPathPrefix(prefix: "/prefix");
transformBuilderContext.AddPathPrefix(prefix: "/prefix");
示例:
/request/path
变为 /prefix/request/path
这将为请求路径加上给定值前缀。
PathRemovePrefix
修改删除前缀值的请求路径
密钥 | 价值 | 必选 |
---|---|---|
PathRemovePrefix | 以“/”开头的路径 | 是的 |
Config:
{ "PathRemovePrefix": "/prefix" }
代码:
routeConfig = routeConfig.WithTransformPathRemovePrefix(prefix: "/prefix");
transformBuilderContext.AddPathRemovePrefix(prefix: "/prefix");
示例:
/prefix/request/path
变为 /request/path
/prefix2/request/path
未修改
这将从请求路径中删除匹配的前缀。 匹配是在路径段边界(/
) 上进行的。 如果前缀不匹配,则不会进行更改。
PathSet
将请求路径替换为指定的值
密钥 | 价值 | 必选 |
---|---|---|
PathSet | 以“/”开头的路径 | 是的 |
Config:
{ "PathSet": "/newpath" }
代码:
routeConfig = routeConfig.WithTransformPathSet(path: "/newpath");
transformBuilderContext.AddPathSet(path: "/newpath");
示例:
/request/path
变为 /newpath
这将使用给定值设置请求路径。
路径模式
使用模式模板替换请求路径
密钥 | 价值 | 必选 |
---|---|---|
路径模式 | 以“/”开头的路径模板 | 是的 |
Config:
{ "PathPattern": "/my/{plugin}/api/{**remainder}" }
代码:
routeConfig = routeConfig.WithTransformPathRouteValues(pattern: new PathString("/my/{plugin}/api/{**remainder}"));
transformBuilderContext.AddPathRouteValues(pattern: new PathString("/my/{plugin}/api/{**remainder}"));
这将使用给定值设置请求路径,并将任何 {}
段替换为关联的路由值。
{}
删除了不带匹配路由值的段。 最后的{}
段可以标记为{**remainder}
,以指示这是一个可能包含多个路径段的总括段。 有关路由模板的详细信息,请参阅 ASP.NET Core 的 路由文档 。
示例:
步骤 | 价值 |
---|---|
路由定义 | /api/{plugin}/stuff/{**remainder} |
请求路径 | /api/v1/stuff/more/stuff |
插件值 | v1 |
余数值 | more/stuff |
路径模式 | /my/{plugin}/api/{**remainder} |
结果 | /my/v1/api/more/stuff |
QueryValueParameter
在请求查询字符串中添加或替换参数
密钥 | 价值 | 必选 |
---|---|---|
QueryValueParameter | 查询字符串参数的名称 | 是的 |
设置/追加 | 静态值 | 是的 |
Config:
{
"QueryValueParameter": "foo",
"Append": "bar"
}
代码:
routeConfig = routeConfig.WithTransformQueryValue(queryKey: "foo", value: "bar", append: true);
transformBuilderContext.AddQueryValue(queryKey: "foo", value: "bar", append: true);
这将添加一个包含名称 foo
的查询字符串参数,并将其设置为静态值 bar
。
示例:
步骤 | 价值 |
---|---|
查询 | ?a=b |
QueryValueParameter | foo |
追加 | remainder |
结果 | ?a=b&foo=remainder |
查询路由参数
使用路由配置中的值添加或替换查询字符串参数
密钥 | 价值 | 必选 |
---|---|---|
查询路由参数 | 查询字符串参数的名称 | 是的 |
设置/追加 | 路由值的名称 | 是的 |
Config:
{
"QueryRouteParameter": "foo",
"Append": "remainder"
}
代码:
routeConfig = routeConfig.WithTransformQueryRouteValue(queryKey: "foo", routeValueKey: "remainder", append: true);
transformBuilderContext.AddQueryRouteValue(queryKey: "foo", routeValueKey: "remainder", append: true);
这将添加一个包含名称 foo
的查询字符串参数,并将其设置为关联的路由值的值。
示例:
步骤 | 价值 |
---|---|
路由定义 | /api/{*remainder} |
请求路径 | /api/more/stuff |
余数值 | more/stuff |
查询路由参数 | foo |
追加 | remainder |
结果 | ?foo=more/stuff |
QueryRemoveParameter
从请求查询字符串中删除指定的参数
密钥 | 价值 | 必选 |
---|---|---|
QueryRemoveParameter | 查询字符串参数的名称 | 是的 |
Config:
{ "QueryRemoveParameter": "foo" }
代码:
routeConfig = routeConfig.WithTransformQueryRemoveKey(queryKey: "foo");
transformBuilderContext.AddQueryRemoveKey(queryKey: "foo");
如果请求中存在,这将删除具有名称 foo
的查询字符串参数。
示例:
步骤 | 价值 |
---|---|
请求路径 | ?a=b&foo=c |
QueryRemoveParameter | foo |
结果 | ?a=b |
HttpMethodChange
更改请求中使用的 http 方法
密钥 | 价值 | 必选 |
---|---|---|
HttpMethodChange | 需要替换的 HTTP 方法 | 是的 |
设置 | 新的 http 方法 | 是的 |
Config:
{
"HttpMethodChange": "PUT",
"Set": "POST"
}
代码:
routeConfig = routeConfig.WithTransformHttpMethodChange(fromHttpMethod: HttpMethods.Put, toHttpMethod: HttpMethods.Post);
transformBuilderContext.AddHttpMethodChange(fromHttpMethod: HttpMethods.Put, toHttpMethod: HttpMethods.Post);
这将将 PUT 请求更改为 POST。
RequestHeadersCopy
设置是否将传入请求标头复制到出站请求
密钥 | 价值 | 违约 | 必选 |
---|---|---|---|
RequestHeadersCopy | 真/假 | 是 | 是的 |
Config:
{ "RequestHeadersCopy": "false" }
代码:
routeConfig = routeConfig.WithTransformCopyRequestHeaders(copy: false);
transformBuilderContext.CopyRequestHeaders = false;
这将设置是否将所有传入请求标头复制到代理请求中。 此设置默认处于启用状态,可通过将转换配置为 false
值来禁用。 即使禁用了此功能,引用特定标头的转换仍将运行。
RequestHeaderOriginalHost
指定是否应将传入请求主机标头复制到代理请求
密钥 | 价值 | 违约 | 必选 |
---|---|---|---|
RequestHeaderOriginalHost | 真/假 | 假 | 是的 |
Config:
{ "RequestHeaderOriginalHost": "true" }
routeConfig = routeConfig.WithTransformUseOriginalHostHeader(useOriginal: true);
transformBuilderContext.AddOriginalHost(true);
这指定是否应将传入请求主机标头复制到代理请求。 此设置默认处于禁用状态,可以通过配置具有 true
值的转换来启用此设置。 直接引用 Host
标头的转换将替代此转换。
RequestHeader
添加或替换请求标头
密钥 | 价值 | 必选 |
---|---|---|
RequestHeader | 标头名称 | 是的 |
设置/追加 | 标头值 | 是的 |
Config:
{
"RequestHeader": "MyHeader",
"Set": "MyValue"
}
代码:
routeConfig = routeConfig.WithTransformRequestHeader(headerName: "MyHeader", value: "MyValue", append: false);
transformBuilderContext.AddRequestHeader(headerName: "MyHeader", value: "MyValue", append: false);
示例:
MyHeader: MyValue
这会设置或追加命名标头的值。 Set 替换任何现有标头。 Append 会添加具有给定值的额外标头。 注意:不建议将“”设置为标头值,并可能导致未定义的行为。
RequestHeaderRouteValue
使用路由配置中的值添加或替换标头
密钥 | 价值 | 必选 |
---|---|---|
RequestHeader | 查询字符串参数的名称 | 是的 |
设置/追加 | 路由值的名称 | 是的 |
Config:
{
"RequestHeaderRouteValue": "MyHeader",
"Set": "MyRouteKey"
}
代码:
routeConfig = routeConfig.WithTransformRequestHeaderRouteValue(headerName: "MyHeader", routeValueKey: "key", append: false);
transformBuilderContext.AddRequestHeaderRouteValue(headerName: "MyHeader", routeValueKey: "key", append: false);
示例:
步骤 | 价值 |
---|---|
路由定义 | /api/{*remainder} |
请求路径 | /api/more/stuff |
余数值 | more/stuff |
RequestHeaderFromRoute | foo |
追加 | remainder |
结果 | foo: more/stuff |
这会使用路由配置中的值来设置或追加命名标头的值。 Set 替换任何现有标头。 Append 会添加具有给定值的额外标头。 注意:不建议将“”设置为标头值,并可能导致未定义的行为。
RequestHeaderRemove
删除请求标头
密钥 | 价值 | 必选 |
---|---|---|
RequestHeaderRemove | 标头名称 | 是的 |
Config:
{
"RequestHeaderRemove": "MyHeader"
}
代码:
routeConfig = routeConfig.WithTransformRequestHeaderRemove(headerName: "MyHeader");
transformBuilderContext.AddRequestHeaderRemove(headerName: "MyHeader");
示例:
MyHeader: MyValue
AnotherHeader: AnotherValue
这会删除命名标头。
RequestHeadersAllowed
密钥 | 价值 | 必选 |
---|---|---|
RequestHeadersAllowed | 以分号分隔的允许标头名称列表。 | 是的 |
Config:
{
"RequestHeadersAllowed": "Header1;header2"
}
代码:
routeConfig = routeConfig.WithTransformRequestHeadersAllowed("Header1", "header2");
transformBuilderContext.AddRequestHeadersAllowed("Header1", "header2");
YARP 默认将大多数请求标头复制到代理请求(请参阅 RequestHeadersCopy)。 某些安全模型仅允许代理特定标头。 此转换将禁用 RequestHeadersCopy,并且仅复制给定标头。 如果未包含在允许列表中,则修改或追加到现有标头的其他转换可能会受到影响。
请注意,默认情况下,某些标头 YARP 不会复制,因为它们特定于连接或其他安全敏感(例如Connection
)。 Alt-Svc
将这些标头名称放在允许列表中将绕过该限制,但强烈建议不要这样做,因为它可能会对代理的功能产生负面影响或导致安全漏洞。
示例:
Header1: value1
Header2: value2
AnotherHeader: AnotherValue
只有 header1 和 header2 被复制到代理请求中。
X 转发
添加包含原始客户端请求信息的标头
密钥 | 价值 | 违约 | 必选 |
---|---|---|---|
X 转发 | 要应用于下面列出的所有 X-Forwarded* 的默认操作(设置、追加、删除、关闭) | 设置 | 是的 |
为 | 要应用于此标头的操作 | * 请参阅 X-Forwarded | 不 |
协议 | 要应用于此标头的操作 | * 请参阅 X-Forwarded | 不 |
主机 | 要应用于此标头的操作 | * 请参阅 X-Forwarded | 不 |
前缀 | 要应用于此标头的操作 | * 请参阅 X-Forwarded | 不 |
HeaderPrefix | 标头名称前缀 | “X-Forwarded-” | 不 |
操作“关闭状态”会完全禁用转换功能。
Config:
{
"X-Forwarded": "Set",
"For": "Remove",
"Proto": "Append",
"Prefix": "Off",
"HeaderPrefix": "X-Forwarded-"
}
代码:
routeConfig = routeConfig.WithTransformXForwarded(
headerPrefix = "X-Forwarded-",
ForwardedTransformActions xDefault = ForwardedTransformActions.Set,
ForwardedTransformActions? xFor = null,
ForwardedTransformActions? xHost = null,
ForwardedTransformActions? xProto = null,
ForwardedTransformActions? xPrefix = null);
transformBuilderContext.AddXForwarded(ForwardedTransformActions.Set);
transformBuilderContext.AddXForwardedFor(headerName: "X-Forwarded-For", ForwardedTransformActions.Append);
transformBuilderContext.AddXForwardedHost(headerName: "X-Forwarded-Host", ForwardedTransformActions.Append);
transformBuilderContext.AddXForwardedProto(headerName: "X-Forwarded-Proto", ForwardedTransformActions.Off);
transformBuilderContext.AddXForwardedPrefix(headerName: "X-Forwarded-Prefix", ForwardedTransformActions.Remove);
示例:
X-Forwarded-For: 5.5.5.5
X-Forwarded-Proto: https
X-Forwarded-Host: IncomingHost:5000
X-Forwarded-Prefix: /path/base
禁用默认标头:
{ "X-Forwarded": "Off" }
transformBuilderContext.UseDefaultForwarders = false;
当代理连接到目标服务器时,连接与客户端对代理建立的连接无关。 目标服务器可能需要原始连接信息进行安全检查,并正确生成链接和重定向的绝对 URI。 若要将有关客户端连接的信息传递给目标,可以添加一组额外的标头。 在Forwarded
标准建立之前,一种常见的解决方案是使用X-Forwarded-*
标头。 没有定义X-Forwarded-*
标头的官方标准,因此实现可能因服务器而异,请检查目标服务器是否支持。
即使路由配置中未指定,也默认启用此转换。
将 X-Forwarded
值设置为包含你需要启用的标头的逗号分隔列表。 默认情况下,所有 for 标头都处于启用状态。 可以通过指定值 "Off"
来禁用所有值。
Prefix 指定要用于每个标头的标头名称前缀。 使用默认X-Forwarded-
前缀时,生成的标头将为X-Forwarded-For
、X-Forwarded-Proto
和X-Forwarded-Host
X-Forwarded-Prefix
。
转换操作指定了如何将每个标头与同名的现有标头组合在一起。 它可以是“Set”、“Append”、“Remove”或“Off”(完全禁用转换功能)。 遍历多个代理的请求可能会累积此类标头的列表,目标服务器需要评估列表以确定原始值。 如果操作是“Set”并且关联的值在请求中不可用(例如 RemoteIpAddress 为 null),则仍会删除现有的任何标头以防止欺骗。
{Prefix}For 标头值取自 HttpContext.Connection.RemoteIpAddress
表示前一个调用方 IP 地址。 不包括端口。 IPv6 地址不包括方括号 []
。
{Prefix}Proto 标头值取自 HttpContext.Request.Scheme
指示前一个调用方是否使用了 HTTP 或 HTTPS。
{Prefix}主机标头值取自传入请求的主机标头。 这独立于上面指定的 RequestHeaderOriginalHost。 Unicode/IDN 主机经过 punycode 编码。
{Prefix}Prefix 标头值取自 HttpContext.Request.PathBase
。 生成代理请求时不使用 PathBase 属性,因此目标服务器需要原始值才能正确生成链接和重定向。 该值采用百分比编码 URI 格式。
转发
添加包含原始客户端请求信息的标头
密钥 | 价值 | 违约 | 必选 |
---|---|---|---|
转发 | 逗号分隔列表,其中包含以下任何值:for、by、proto、host | (无) | 是的 |
ForFormat | Random/RandomAndPort/RandomAndRandomPort/Unknown/UnknownAndPort/unknownAndRandomPort/ip/IpAndPort/IpAndRandomPort | 随机 | 不 |
ByFormat | Random/RandomAndPort/RandomAndRandomPort/Unknown/UnknownAndPort/unknownAndRandomPort/ip/IpAndPort/IpAndRandomPort | 随机 | 不 |
行动 | 应用于此标头的操作(设置、附加、删除、关闭) | 设置 | 不 |
Config:
{
"Forwarded": "by,for,host,proto",
"ByFormat": "Random",
"ForFormat": "IpAndPort",
"Action": "Append"
},
代码:
routeConfig = routeConfig.WithTransformForwarded(useHost: true, useProto: true, forFormat: NodeFormat.IpAndPort, ByFormat: NodeFormat.Random, action: ForwardedTransformAction.Append);
transformBuilderContext.AddForwarded(useHost: true, useProto: true, forFormat: NodeFormat.IpAndPort, ByFormat: NodeFormat.Random, action: ForwardedTransformAction.Append);
示例:
Forwarded: proto=https;host="localhost:5001";for="[::1]:20173";by=_YQuN68tm6
标头 Forwarded
由 RFC 7239 定义。 它整合了与非官方 X-Forwarded 标头相同的许多功能,将信息流向目标服务器,否则将使用代理隐藏这些信息。
启用此转换将禁用默认的 X-Forwarded 转换,因为它们以其他格式传递类似的信息。 仍可以显式启用 X-Forwarded 转换。
操作:这指定转换应如何处理现有的 Forwarded 标头。 它可以是“Set”、“Append”、“Remove”或“Off”(完全禁用转换功能)。 遍历多个代理的请求可能会累积此类标头的列表,目标服务器需要评估列表以确定原始值。
Proto:此值取自 HttpContext.Request.Scheme
指示前一个调用方是否使用了 HTTP 或 HTTPS。
主机:此值取自传入请求的主机标头。 这独立于上面指定的 RequestHeaderOriginalHost。 Unicode/IDN 主机经过 punycode 编码。
对于:此值标识以前的调用方。 IP 地址取自 HttpContext.Connection.RemoteIpAddress
。 有关详细信息,请参阅下面的 ByFormat 和 ForFormat。
接收源:此值标识代理接收请求的位置。 IP 地址取自 HttpContext.Connection.LocalIpAddress
。 有关详细信息,请参阅下面的 ByFormat 和 ForFormat。
ByFormat 和 ForFormat:
RFC 允许 By 和 For 字段 的各种格式 。 它要求默认格式使用此处标识为 Random 的经过模糊处理的标识符。
格式 | DESCRIPTION | 示例: |
---|---|---|
随机 | 每个请求随机生成的经过模糊处理的标识符。 这允许诊断跟踪方案,同时出于隐私原因限制唯一标识信息的流。 | by=_YQuN68tm6 |
RandomAndPort | 随机标识符加上端口。 | by="_YQuN68tm6:80" |
RandomAndRandomPort | 随机标识符加上端口的另一个随机标识符。 | by="_YQuN68tm6:_jDw5Cf3tQ" |
未知 | 如果上述实体的标识未知,但代理服务器仍希望表明请求已转发,则可以使用此方法。 | by=unknown |
UnknownAndPort | 未知标识符和端口(如果可用)。 | by="unknown:80" |
UnknownAndRandomPort | 端口的未知标识符和随机标识符。 | by="unknown:_jDw5Cf3tQ" |
Ip | IPv4 地址或 IPv6 地址,包括括号。 | by="[::1]" |
IpAndPort | IP 地址和端口。 | by="[::1]:80" |
IpAndRandomPort | 端口的 IP 地址加上随机标识符。 | by="[::1]:_jDw5Cf3tQ" |
ClientCert
将入站连接上使用的客户端证书作为标头转发到目标
密钥 | 价值 | 必选 |
---|---|---|
ClientCert | 标头名称 | 是的 |
Config:
{ "ClientCert": "X-Client-Cert" }
代码:
routeConfig = routeConfig.WithTransformClientCertHeader(headerName: "X-Client-Cert");
transformBuilderContext.AddClientCertHeader(headerName: "X-Client-Cert");
示例:
X-Client-Cert: SSdtIGEgY2VydGlmaWNhdGU...
由于入站和出站连接是独立的,因此需要有一种方法将任何入站客户端证书传递到目标服务器。 此转换会导致从 HttpContext.Connection.ClientCertificate
中获取的客户端证书进行 Base64 编码,并设置为给定标头名称的值。 目标服务器可能需要该证书对客户端进行身份验证。 没有定义该标头的标准,不同的实现方式可能为此有所不同,请检查目标服务器是否支持。
默认情况下,服务器对传入客户端证书进行最小验证。 应在代理或目标中验证证书,有关详细信息,请参阅 客户端证书身份验证 文档。
仅当连接上已存在客户端证书时,此转换才适用。 如果需要根据每个路由从客户端请求证书,请参阅 可选证书文档 。