aspnetcore/fundamentals/servers/yarp/http-client-config.md
Each Cluster has a dedicated HttpMessageInvoker instance used to forward requests to its Destinations. The configuration is defined per cluster. On YARP startup, all clusters get new HttpMessageInvoker instances, however if later the cluster configuration gets changed the IForwarderHttpClientFactory will re-run and decide if it should create a new HttpMessageInvoker or keep using the existing one. The default IForwarderHttpClientFactory implementation creates a new HttpMessageInvoker when there are changes to the HttpClientConfig.
Properties of outgoing requests for a given cluster can be configured as well. They are defined in ForwarderRequestConfig.
The configuration is represented differently if you're using the IConfiguration model or the code-first model.
These types are focused on defining serializable configuration. The code based configuration model is described below in the "Code Configuration" section.
HTTP client configuration is based on HttpClientConfig and represented by the following configuration schema. If you need a more granular approach, use a <!--check link--> custom implementation of IForwarderHttpClientFactory.
"HttpClient": {
"SslProtocols": [ "<protocol-names>" ],
"MaxConnectionsPerServer": "<int>",
"DangerousAcceptAnyServerCertificate": "<bool>",
"RequestHeaderEncoding": "<encoding-name>",
"ResponseHeaderEncoding": "<encoding-name>",
"EnableMultipleHttp2Connections": "<bool>",
"WebProxy": {
"Address": "<url>",
"BypassOnLocal": "<bool>",
"UseDefaultCredentials": "<bool>"
}
}
Configuration settings:
"SslProtocols": [
"Tls11",
"Tls12"
]
"MaxConnectionsPerServer": "10"
true completely disables validation. Default value is false."DangerousAcceptAnyServerCertificate": "true"
SocketsHttpHandler.RequestHeaderEncodingSelector and use the selected encoding for all headers. The value is then parsed by Encoding.GetEncoding, use values like: "utf-8", "iso-8859-1", etc."RequestHeaderEncoding": "utf-8"
SocketsHttpHandler.ResponseHeaderEncodingSelector and use the selected encoding for all headers. The value is then parsed by Encoding.GetEncoding, use values like: "utf-8", "iso-8859-1", etc."ResponseHeaderEncoding": "utf-8"
Note that if you're using an encoding other than ASCII, you also need to set your server to accept requests and/or send responses with such headers. For example, when using Kestrel as the server, use KestrelServerOptions.RequestHeaderEncodingSelector / .ResponseHeaderEncodingSelector to configure Kestrel to allow Latin1 ("iso-8859-1") headers:
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel(kestrel =>
{
kestrel.RequestHeaderEncodingSelector = _ => Encoding.Latin1;
// and/or
kestrel.ResponseHeaderEncodingSelector = _ => Encoding.Latin1;
});
true. See SocketsHttpHandler.EnableMultipleHttp2Connections"EnableMultipleHttp2Connections": false
SocketsHttpHandler.Proxy for details.
"WebProxy": {
"Address": "http://myproxy:8080",
"BypassOnLocal": "true",
"UseDefaultCredentials": "false"
}
[!NOTE] The default
ForwarderHttpClientFactorysetsUseProxytofalse. If you want to use the default system proxy instead of specifying a custom proxy address, you can setUseProxyback totrueusing theConfigureHttpClientmethod. This is useful when debugging with tools like Fiddler. See the Configuring the http client section for an example.
HTTP request configuration is based on ForwarderRequestConfig and represented by the following configuration schema.
"HttpRequest": {
"ActivityTimeout": "<timespan>",
"Version": "<string>",
"VersionPolicy": ["RequestVersionOrLower", "RequestVersionOrHigher", "RequestVersionExact"],
"AllowResponseBuffering": "<bool>"
}
Configuration settings:
1.0, 1.1, 2 and 3. Default value is 2.RequestVersionOrLower.The below example shows 2 samples of HTTP client and request configurations for cluster1 and cluster2.
{
"Clusters": {
"cluster1": {
"LoadBalancingPolicy": "Random",
"HttpClient": {
"SslProtocols": [
"Tls11",
"Tls12"
],
"MaxConnectionsPerServer": "10",
"DangerousAcceptAnyServerCertificate": "true"
},
"HttpRequest": {
"ActivityTimeout": "00:00:30"
},
"Destinations": {
"cluster1/destination1": {
"Address": "https://localhost:10000/"
},
"cluster1/destination2": {
"Address": "http://localhost:10010/"
}
}
},
"cluster2": {
"HttpClient": {
"SslProtocols": [
"Tls12"
]
},
"HttpRequest": {
"Version": "1.1",
"VersionPolicy": "RequestVersionExact"
},
"Destinations": {
"cluster2/destination1": {
"Address": "https://localhost:10001/"
}
}
}
}
}
HTTP client configuration uses the type HttpClientConfig.
The following is an example of HttpClientConfig using code based configuration. An instance of HttpClientConfig is assigned to the ClusterConfig.HttpClient property before passing the cluster array to LoadFromMemory method.
var routes = new[]
{
new RouteConfig()
{
RouteId = "route1",
ClusterId = "cluster1",
Match =
{
Path = "{**catch-all}"
}
}
};
var clusters = new[]
{
new ClusterConfig()
{
ClusterId = "cluster1",
Destinations =
{
{ "destination1", new DestinationConfig() { Address = "https://localhost:10000" } }
},
HttpClient = new HttpClientConfig { MaxConnectionsPerServer = 10, SslProtocols = SslProtocols.Tls11 | SslProtocols.Tls12 }
}
};
services.AddReverseProxy()
.LoadFromMemory(routes, clusters);
ConfigureHttpClient provides a callback to customize the SocketsHttpHandler settings used for proxying requests. This will be called each time a cluster is added or changed. Cluster settings are applied to the handler before the callback. Custom data can be provided in the cluster metadata. This example shows adding a client certificate that will authenticate the proxy to the destination servers.
var clientCert = new X509Certificate2("path");
services.AddReverseProxy()
.ConfigureHttpClient((context, handler) =>
{
handler.SslOptions.ClientCertificates.Add(clientCert);
});
The default ForwarderHttpClientFactory sets UseProxy to false to avoid the overhead of proxy detection and configuration. If you need to use the default system proxy (for example, when debugging with Fiddler or other proxy tools), you can set UseProxy back to true:
services.AddReverseProxy()
.ConfigureHttpClient((context, handler) =>
{
handler.UseProxy = true;
});
This configuration allows the HttpClient to use the system's default proxy settings without having to manually specify a proxy address in the WebProxy configuration.
If direct control of HTTP client construction is necessary, the default IForwarderHttpClientFactory can be replaced with a custom one. For some customizations you can derive from the default ForwarderHttpClientFactory and override the methods that configure the client.
It's recommended that any custom factory set the following SocketsHttpHandler properties to the same values as the default factory does in order to preserve a correct reverse proxy behavior and avoid unnecessary overhead.
new SocketsHttpHandler
{
UseProxy = false,
AllowAutoRedirect = false,
AutomaticDecompression = DecompressionMethods.None,
UseCookies = false,
EnableMultipleHttp2Connections = true,
ActivityHeadersPropagator = new ReverseProxyPropagator(DistributedContextPropagator.Current),
ConnectTimeout = TimeSpan.FromSeconds(15),
};
Always return an HttpMessageInvoker instance rather than an HttpClient instance which derives from HttpMessageInvoker. HttpClient buffers responses by default which breaks streaming scenarios and increases memory usage and latency.
Custom data can be provided in the cluster metadata.
The below is an example of a custom IForwarderHttpClientFactory implementation.
public class CustomForwarderHttpClientFactory : IForwarderHttpClientFactory
{
public HttpMessageInvoker CreateClient(ForwarderHttpClientContext context)
{
var handler = new SocketsHttpHandler
{
UseProxy = false,
AllowAutoRedirect = false,
AutomaticDecompression = DecompressionMethods.None,
UseCookies = false,
EnableMultipleHttp2Connections = true,
ActivityHeadersPropagator = new ReverseProxyPropagator(DistributedContextPropagator.Current),
ConnectTimeout = TimeSpan.FromSeconds(15),
};
return new HttpMessageInvoker(handler, disposeHandler: true);
}
}