在后端服务中创建自定义标头

本页面介绍了如何在全球外部应用负载均衡器使用的后端服务中配置自定义标头。

使用自定义请求和响应标头,您可以指定负载均衡器可以添加到 HTTP(S) 请求和响应中的额外标头。根据负载均衡器检测到的信息,这些标头可以包含以下信息:

  • 客户端的延迟时间
  • 客户端 IP 地址的地理位置
  • TLS 连接的参数

后端服务支持自定义请求标头,而后端服务和后端存储桶支持自定义响应标头。

默认情况下,负载均衡器会将某些标头添加到其作为代理在后端与客户端之间处理的所有 HTTP(S) 请求和响应。如需了解详情,请参阅目标代理

准备工作

  • 如有必要,请更新到 Google Cloud CLI 的最新版本:

    gcloud components update
    

自定义标头的工作原理

自定义标头的工作原理如下:

  • 当负载均衡器向后端转发请求时,负载均衡器会添加请求标头。

    负载均衡器仅会向客户端请求添加自定义请求标头,而不会向健康检查探测添加自定义请求标头。如果后端需要将特定标头用于授权,而健康检查数据包中缺少该标头,则健康检查可能会失败。

  • 负载均衡器会在将响应返回给客户端之前设置响应标头。

要启用自定义标头,您可以在后端服务或后端存储桶的属性中指定标头列表。

您可以将每个标头指定为 header-name:header-value 字符串。标头必须包含用于分隔标头名称和标头值的英文冒号。

标头名称必须符合以下要求:

  • 标头名称必须是有效的 HTTP 标头字段名称定义(根据 RFC 7230)。
  • Host 标头可以配置,但受某些限制的约束。
  • 标头名称不得为 authority。 这是一个由 Google Cloud 保留的特殊关键字。您无法为基于 Envoy 的负载均衡器(如全球外部应用负载均衡器)修改此标头。相反,我们建议您创建其他自定义标头,以免干扰预留的标头名称。
  • 标头名称不得为 X-User-IPCDN-Loop
  • 不得使用以下跃点标头:Keep-AliveTransfer-EncodingTEConnectionTrailerUpgradeProxy-AuthorizationProxy-Authenticate。根据 RFC 2616,这些标头不会由缓存存储,也不会由目标代理传播。
  • 标头名称不得以 X-GoogleX-Goog-X-GFEX-Amz- 开头。
  • 标头名称不能在已添加标头的列表中出现多次。

标头值必须符合以下要求:

  • 标头值必须是有效的 HTTP 标头字段定义(根据 RFC 7230,不允许使用已过时的格式)。
  • 标头值可以为空。
  • 标头值可以包含一个或多个由花括号括起来的变量,这些变量可扩展为负载均衡器提供的值。标头值中允许使用的变量列表将在下一部分中介绍。

gcloud 命令行工具有一个用于指定请求标头的标志,即 --custom-request-header。使用此标志时,请务必将标头名称和标头值用直引号 (') 括起来。

该标志的常规格式如下:

    --custom-request-header='HEADER_NAME:[HEADER_VALUE]'

以下示例展示了包含两个变量(client_regionclient_city,用大括号括起)的标头值。

    --custom-request-header='X-Client-Geo-Location:{client_region},{client_city}'

如果客户端位于加利福尼亚州山景城,则负载均衡器会添加如下所示的标头:

X-Client-Geo-Location:US,Mountain View

如需使用自定义标头创建后端服务,请参阅配置自定义请求标头

主机标头

使用全球外部应用负载均衡器配置自定义 Host 标头时,存在以下限制:

  • 只有在您要替换现有 Host 请求标头时,才能配置自定义 Host 请求标头。
  • 无法通过在网址映射中使用标头操作来配置自定义 Host 响应标头。但是,您仍然可以在后端服务中配置自定义 Host 响应标头。
  • 此外,以下内容适用于请求标头和响应标头:
    • 无法附加或移除自定义 Host 标头。
    • 无法将变量与自定义 Host 标头搭配使用。

标头值支持的变量

以下变量可以出现在自定义标头值中。

变量 说明
cdn_cache_id 用于传送请求的缓存实例的位置代码和 ID。此值与 Logging 中 Cloud CDN 请求日志的 jsonPayload.cacheId 字段中填充的值相同。
cdn_cache_status 当前缓存状态。对于启用 Cloud CDN 的后端传送的任何对象,值可以是 hitmissrevalidatedstaleuncacheabledisabled
origin_request_header 反映的是请求中跨域资源共享 (CORS) 用例的 Origin 标头的值。
client_rtt_msec 负载均衡器与 HTTP(S) 客户端之间的预计往返传输时间,以毫秒为单位。这是负载均衡器的 TCP 堆栈根据 RFC 2988 测量的平滑往返时间 (SRTT) 参数。 平滑 RTT 是一种算法,用于处理 RTT 测量中可能发生的变体和异常。
client_region 与客户端 IP 地址相关联的国家/地区(或区域)。这是一个 Unicode CLDR 区域代码,例如 USFR。(对于大多数国家/地区,这些代码直接对应于 ISO-3166-2 代码。)
client_region_subdivision 与客户端 IP 地址相关联的国家/地区的下属行政单位,例如省或州。这是一个 Unicode CLDR 下属行政单位 ID,例如 USCACAON。(这些 Unicode 代码从 ISO-3166-2 标准定义的下属行政单位派生而来。)
client_city 发起请求的城市名称,例如表示加利福尼亚州山景城的 Mountain View。此变量没有标准的有效值列表。城市名称可以包含 US-ASCII 字母、数字、空格和以下字符:!#$%&'*+-.^_`|~
client_city_lat_long 发出请求的城市的纬度和经度,例如 37.386051,-122.083851(表示请求来自山景城)。
client_ip_address 客户端的 IP 地址。除非客户端使用代理,或者 X-Forwarded-For 标头已被篡改,否则这通常与 X-Forwarded-For 标头中属于倒数第二个地址的客户端 IP 地址相同。
client_port 客户端的来源端口。
client_encrypted 如果客户端和负载均衡器之间的连接已加密(使用 HTTPS、HTTP/2 或 HTTP/3),则为 true;否则为 false
client_protocol 用于客户端和负载均衡器之间通信的 HTTP 协议。HTTP/1.0HTTP/1.1HTTP/2HTTP/3 之一。
server_ip_address 客户端所连接的负载均衡器的 IP 地址。这在多个负载均衡器共享公共后端时非常有用。这与 X-Forwarded-For 标头中的最后一个 IP 地址相同。
server_port 客户端所连接的目标端口号。
tls_sni_hostname 由客户端在 TLS 或 QUIC 握手期间提供的服务器名称指示(如 RFC 6066 中所定义)。系统会将主机名转换为小写字母并移除结尾的任何英文句点。
tls_version 客户端与负载均衡器在 SSL 握手期间协商的 TLS 版本。可能的值包括 TLSv1TLSv1.1TLSv1.2TLSv1.3。如果客户端使用 QUIC(而不是 TLS)进行连接,则值将为 QUIC
tls_cipher_suite 在 TLS 握手期间协商的加密套件。该值是由 IANA TLS 加密套件注册系统定义的四位十六进制数字,例如表示 TLS_RSA_WITH_AES_128_GCM_SHA256 的 009C。对于 QUIC 和未加密的客户端连接,此值为空。
tls_ja3_fingerprint JA3 TLS/SSL 指纹(如果客户端使用 HTTPS、HTTP/2 或 HTTP/3 进行连接)。

负载均衡器在无法确定变量值时会将变量扩展为空字符串。例如:

  • IP 地址的位置未知时的地理位置变量
  • 未使用 TLS 时的 TLS 参数
  • 请求不包含 Origin 标头时的 {origin_request_header}
  • 请求标头中包含时的 {cdn_cache_status} 标头

地理位置值(区域、下属行政单位和城市)是根据客户端 IP 地址估算的值。Google 会不时地更新提供这些值的数据,以便提高准确性并反映地理和政治方面的变化。即使原始 X-Forwarded-For 标头包含有效的位置信息,Google 也会使用负载均衡器收到的数据包中包含的来源 IP 地址信息来估算客户端位置。

负载均衡器添加的标头会覆盖任何同名的现有标头。标头名称不区分大小写。当标头名称传递至 HTTP/2 后端时,HTTP/2 协议会将标头名称编码为小写。

在标头值中,前导空格和尾随空格无意义,因此不会传递至后端。为了允许在标头值中使用花括号,负载均衡器会将两个左花括号 ({{) 解释为一个左花括号 ({),而将两个右花括号 (}}) 解释为一个右花括号 (})。

双向 TLS 自定义标头

如果在负载均衡器的 TargetHttpsProxy 上配置了双向 TLS (mTLS),则可以使用以下额外的标头变量。

变量 说明
client_cert_present 如果客户端在 TLS 握手期间提供了证书,则为 true;否则为 false
client_cert_chain_verified 如果根据配置的 TrustStore 验证了客户端证书链,则为 true;否则为 false
client_cert_error 代表错误情况的预定义字符串。如需详细了解错误字符串,请参阅 mTLS 客户端验证模式
client_cert_sha256_fingerprint 客户端证书的 Base64 编码 SHA-256 指纹。
client_cert_serial_number 客户端证书的序列号。如果序列号超过 50 字节,则 client_cert_error 设置为 client_cert_serial_number_exceeded_size_limit,序列号设置为空字符串。
client_cert_spiffe_id

主题备用名称 (SAN) 字段中的 SPIFFE ID。如果值无效或超过 2048 字节,则 SPIFFE ID 设置为空字符串。

如果 SPIFFE ID 长度超过 2048 字节,则 client_cert_error 设置为 client_cert_spiffe_id_exceeded_size_limit

client_cert_uri_sans

URI 类型 SAN 扩展的 Base64 编码列表(以逗号分隔)。 SAN 扩展从客户端证书中提取。 client_cert_uri_sans 字段中不包含 SPIFFE ID。

如果 client_cert_uri_sans 长度超过 512 字节,则 client_cert_error 设置为 client_cert_uri_sans_exceeded_size_limit,逗号分隔列表设置为空字符串。

client_cert_dnsname_sans

DNSName 类型 SAN 扩展的 Base64 编码列表(以逗号分隔)。SAN 扩展从客户端证书中提取。

如果 client_cert_dnsname_sans 长度超过 512 字节,则 client_cert_error 设置为 client_cert_dnsname_sans_exceeded_size_limit,逗号分隔列表设置为空字符串。

client_cert_valid_not_before 在此时间戳(RFC 3339 日期字符串格式)之前,客户端证书无效。 例如 2022-07-01T18:05:09+00:00
client_cert_valid_not_after 在此时间戳(RFC 3339 日期字符串格式)之后,客户端证书无效。 例如 2022-07-01T18:05:09+00:00
client_cert_issuer_dn

证书中完整“颁发者”字段的 base64 编码的 DER 编码。

如果 client_cert_issuer_dn 长度超过 512 字节,则将字符串 client_cert_issuer_dn_exceeded_size_limit 添加到 client_cert_error,并将 client_cert_issuer_dn 设置为空字符串。

client_cert_subject_dn

证书中完整“主题”字段的 base64 编码的 DER 编码。

如果 client_cert_subject_dn 长度超过 512 字节,则将字符串 client_cert_subject_dn_exceeded_size_limit 添加到 client_cert_error,并将 client_cert_subject_dn 设置为空字符串。

client_cert_leaf

已建立的 mTLS 连接(证书在其中通过了验证)的客户端叶证书。证书编码符合 RFC 9440 标准。这表示二进制 DER 证书使用 Base64 编码,且任一侧用英文冒号分隔。

如果 client_cert_leaf 超过 16 KB(未编码),则将字符串 client_cert_validated_leaf_exceeded_size_limit 添加到 client_cert_error,并将 client_cert_leaf 设置为空字符串。

client_cert_chain

已建立的 mTLS 连接(客户端证书在其中通过了验证)的客户端证书链的英文逗号分隔证书列表(按标准 TLS 顺序排列),不包括叶证书。证书编码符合 RFC 9440 标准。

如果 client_cert_leafclient_cert_chain 的总大小在 Base64 编码之前超过 16 KB,则将字符串 client_cert_validated_chain_exceeded_size_limit 添加到 client_cert_error,并将 client_cert_chain 设置为空字符串。

配置自定义请求标头

控制台

要向现有后端服务添加自定义请求标头,请执行以下操作:

  1. 转到负载均衡摘要页面。
    转到“负载均衡”页面
  2. 点击后端
  3. 点击后端服务的名称。
  4. 点击修改
  5. 点击 Advanced configurations (Session affinity, connection draining timeout, security policies)(高级配置 [会话亲和性、连接排空超时时间、安全政策])。
  6. 自定义请求标头下,点击添加标头 (Add header)。
  7. 输入自定义请求标头的标头名称标头值
  8. 输入其他任何自定义请求标头。
  9. 点击保存

要从后端服务中移除自定义请求标头,请执行以下操作:

  1. 转到负载均衡摘要页面。
    转到“负载均衡”页面
  2. 点击后端
  3. 点击后端服务的名称。
  4. 点击修改
  5. 点击 Advanced configurations (Session affinity, connection draining timeout, security policies)(高级配置 [会话亲和性、连接排空超时时间、安全政策])。
  6. 点击您要移除的自定义请求标头名称旁边的 X
  7. 点击保存

gcloud

如需指定自定义请求标头,请使用带有 --custom-request-header 标志的 gcloud compute backend-services creategcloud compute backend-services update 命令。

要使用自定义请求标头创建后端服务,请运行以下命令:

gcloud compute backend-services create BACKEND_SERVICE_NAME \
    --global-health-checks \
    --global \
    --protocol HTTPS \
    --health-checks https-basic-check \
    --custom-request-header='HEADER_NAME:[HEADER_VALUE]'

要添加更多请求标头,请通过重复使用 --custom-request-header 标志来指定唯一的标头名称和值。

要向现有后端服务添加自定义标头,请运行以下命令:

gcloud compute backend-services update BACKEND_SERVICE_NAME \
    --global \
    --custom-request-header='HEADER_1_NAME:[HEADER_1_VALUE]' \
    --custom-request-header='HEADER_2_NAME:[HEADER_2_VALUE]'

上一步会将后端服务中已经存在的任何标头替换为您在该命令中指定的请求标头。

要从后端服务移除所有标头,请运行以下命令:

gcloud compute backend-services update BACKEND_SERVICE_NAME \
    --global \
    --no-custom-request-headers

API

backendServices.patch 方法发出 PATCH 请求。

PATCH https://compute.googleapis.com/compute/v1/projects/PROJECT_ID/global/backendServices/BACKEND_SERVICE_NAME
"customRequestHeaders": [
   "client_city:Mountain View"
]

配置自定义响应标头

控制台

要向现有后端服务添加自定义响应标头,请执行以下操作:

  1. 转到负载均衡摘要页面。
    转到“负载均衡”页面
  2. 点击后端
  3. 点击后端服务的名称。
  4. 点击修改
  5. 点击 Advanced configurations (Session affinity, connection draining timeout, security policies)(高级配置 [会话亲和性、连接排空超时时间、安全政策])。
  6. 自定义响应标头下,点击添加标头
  7. 输入自定义响应标头的标头名称标头值
  8. 输入其他任何自定义响应标头。
  9. 点击保存

要从后端服务中移除自定义响应标头,请执行以下操作:

  1. 转到负载均衡摘要页面。
    转到“负载均衡”页面
  2. 点击后端
  3. 点击后端服务的名称。
  4. 点击修改
  5. 点击 Advanced configurations (Session affinity, connection draining timeout, security policies)(高级配置 [会话亲和性、连接排空超时时间、安全政策])。
  6. 点击您要移除的自定义响应标头名称旁边的 X
  7. 点击保存

gcloud

对于后端服务,请使用带有 --custom-response-header 标志的 gcloud compute backend-services creategcloud compute backend-services update 命令。

对于后端存储桶,请使用带有 --custom-response-header 标志的 gcloud compute backend-buckets creategcloud compute backend-buckets update 命令。

gcloud compute backend-services (create | update) BACKEND_SERVICE_NAME
    --custom-response-header='HEADER_NAME:[HEADER_VALUE]'
gcloud compute backend-buckets (create | update) BACKEND_BUCKET_NAME
    --custom-response-header='HEADER_NAME:[HEADER_VALUE]'

使用 X-Frame-Options 标头的示例:

gcloud compute backend-buckets update gaming-lab \
    --custom-response-header='X-Frame-Options: DENY'

使用 Strict-Transport-Security 标头的示例:

以下示例展示了如何添加自定义响应标头以支持 HTTP 严格传输安全协议 (HSTS):

gcloud compute backend-services update customer-bs-name \
    --global \
    --custom-response-header='Strict-Transport-Security: max-age=63072000'

API

对于后端存储桶,请使用 Method: backendBuckets.insertMethod: backendBuckets.update API 调用。

对于后端服务,请使用 Method: backendServices.insertMethod: backendServices.update API 调用。

使用以下 API 调用之一:

POST https://compute.googleapis.com/compute/v1/projects/PROJECT_ID/global/backendBuckets

PUT https://compute.googleapis.com/compute/v1/projects/PROJECT_ID/global/backendBuckets/BACKEND_BUCKET_NAME

POST https://compute.googleapis.com/compute/v1/projects/PROJECT_ID/global/backendServices

PUT https://compute.googleapis.com/compute/v1/projects/PROJECT_ID/global/backendServices/BACKEND_SERVICE_NAME

将以下代码段添加到 JSON 请求正文:

"customResponseHeaders":HEADER_NAME:[HEADER_VALUE]

设置 Cloud Storage 的响应标头

如果您需要对 Cloud Storage 的响应设置 HTTP 标头(例如跨域资源政策、X-Frame-OptionsX-XSS-Protection 标头),Google Cloud 提供了将 Cloud CDN 自定义标头与 Cloud Storage 搭配使用的选项。为此,您可以在负载均衡器后端存储桶级层配置自定义标头,如本页面所述。

只有在客户端请求发送到负载均衡器 IP 地址时,在后端存储桶级层配置的自定义响应标头才会添加到响应中。如果客户端的请求直接发送到 Cloud Storage API,则自定义标头不会添加到响应中。

将自定义标头与 Google Cloud Armor 搭配使用

配置 Google Cloud Armor 安全政策时,您可以配置 Google Cloud Armor 以插入自定义标头和值。如果 Google Cloud Armor 安全政策配置为插入与全球外部应用负载均衡器或经典版应用负载均衡器的自定义标头相同的自定义标头名称,则 Google Cloud Armor 安全政策中指定的标头值会被负载均衡器填充的值覆盖。如果您不希望覆盖 Google Cloud Armor 政策,请确保不要使用相同的名称。

限制

以下限制适用于在全球负载均衡器中使用自定义标头的情况:

  • 每个后端服务的所有自定义请求标头(名称和值组合,且在变量扩展之前)的总大小不得超过 8 KB 或 16 个请求标头。
  • 每个后端服务的所有自定义响应标头(名称和值组合,且在变量扩展之前)的总大小不得超过 8 KB 或 16 个响应标头。