请求转换包括请求路径、查询、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-HostX-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 编码,并设置为给定标头名称的值。 目标服务器可能需要该证书对客户端进行身份验证。 没有定义该标头的标准,不同的实现方式可能为此有所不同,请检查目标服务器是否支持。
默认情况下,服务器对传入客户端证书进行最小验证。 应在代理或目标中验证证书,有关详细信息,请参阅 客户端证书身份验证 文档。
仅当连接上已存在客户端证书时,此转换才适用。 如果需要根据每个路由从客户端请求证书,请参阅 可选证书文档 。