All Products
Search
Document Center

Alibaba Cloud Service Mesh:Customize request and response headers with VirtualService

Last Updated:Mar 11, 2026

When routing traffic through a service mesh, you often need to inject tracing IDs, enforce security policies, or pass metadata between services. Service Mesh (ASM) supports HTTP header manipulation at the route level through the headers field of the VirtualService CustomResourceDefinition (CRD). You can add, overwrite, or remove headers on both requests and responses without modifying application code.

Prerequisites

Before you begin, ensure that you have:

Header operations reference

VirtualService provides three operations for manipulating headers:

Operation

YAML field

Behavior

Value type

add

headers.request.add / headers.response.add

Adds the specified header with the given value. If the header does not exist, it is created.

map<string, string>

set

headers.request.set / headers.response.set

Overwrites the header value. Creates the header if it does not exist.

map<string, string>

remove

headers.request.remove / headers.response.remove

Deletes the header entirely.

string[]

Static and dynamic header values

Header values can be static strings or dynamic Envoy command operators enclosed in % symbols. For example, %UPSTREAM_CLUSTER% indicates the name of a service provider. All HTTP command operators used for access logs can be specified in custom request or response headers.

Variable

Description

%START_TIME%

Timestamp when the request started

%UPSTREAM_CLUSTER%

Name of the upstream service cluster

Configure header manipulation

The following VirtualService configuration demonstrates all three operations on both request and response headers:

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: httpbin-vs
spec:
  gateways:
    - httpbin
  hosts:
    - '*'
  http:
  - route:
    - destination:
        host: httpbin
        port:
          number: 8000
      weight: 100
    headers:
      request:
        add:
          x-custom-request-header: "custom-value"       # Append a static value
          x-dynamic-request-header: "%START_TIME%"       # Append a dynamic value
        set:
          x-another-request-header: "another-value"      # Overwrite or create
        remove:
          - x-unwanted-header                            # Delete entirely
      response:
        add:
          x-custom-response-header: "custom-response-value"
        set:
          x-another-response-header: "another-response-value"
        remove:
          - x-unwanted-response-header

This configuration applies the following changes:

Request headers

  • Adds x-custom-request-header with the static value custom-value.

  • Adds x-dynamic-request-header with the request start timestamp, resolved at runtime from %START_TIME%.

  • Overwrites x-another-request-header with the value another-value. If this header does not exist, it is created.

  • Removes x-unwanted-header.

Response headers

  • Adds x-custom-response-header with the value custom-response-value.

  • Overwrites x-another-response-header with the value another-response-value. If this header does not exist, it is created.

  • Removes x-unwanted-response-header.

Note

The VirtualService CRD can be used to set and modify HTTP headers. However, Envoy access logs do not record these changes if Envoy retains the default configurations of access logs. If you want to record custom headers in Envoy access logs, you must modify the log format of Envoy.

Verify custom headers in access logs

ASM allows you to customize log formats. The custom expressions of access logs can obtain values from request headers, response headers, and Envoy built-in values. For instructions, see Customize the format of access logs.

Add the following fields to your access log format:

Field name

Type

Log format expression

my-x-custom-request-header

Request attribute

%REQ(x-custom-request-header)%

my-x-dynamic-request-header

Request attribute

%REQ(x-dynamic-request-header)%

my-x-custom-response-header

Response attribute

%RESP(x-custom-response-header)%

Warning

Response headers modified by VirtualService may not appear in access logs if Envoy applies the modification after the logging step in its filter chain. This is expected behavior, not a configuration error. See the HTTPBin pod example below.

After you update the log format, check the access logs for both the gateway pod and the HTTPBin pod.

Gateway pod access log

The gateway pod captures both request and response header modifications:

{
    "bytes_received": "9",
    "bytes_sent": "33",
    "response_code": "200",
    "my-x-custom-request-header": "custom-value",
    "my-x-dynamic-request-header": "2024-01-16T14:49:21.187Z",
    "my-x-custom-response-header": "custom-response-value"
}

HTTPBin pod access log

The HTTPBin sidecar does not capture response headers added by VirtualService because the modification occurs after the sidecar's logging point. The my-x-custom-response-header field shows -:

{
    "bytes_received": "9",
    "bytes_sent": "33",
    "response_code": "200",
    "my-x-custom-request-header": "custom-value",
    "my-x-dynamic-request-header": "2024-01-16T14:49:21.187Z",
    "my-x-custom-response-header": "-"
}