Nguon: Microsoft Learn · .NET 8.0

YARP HTTP Client Configuration (Cấu hình HTTP Client của YARP)

Nguồn: YARP HTTP Client Configuration

Giới thiệu

Mỗi Cluster có một instance HttpMessageInvoker riêng được sử dụng để chuyển tiếp các yêu cầu đến các Destination của nó. Cấu hình được định nghĩa theo từng cluster. Khi khởi động YARP, tất cả các cluster đều nhận được instance HttpMessageInvoker mới, tuy nhiên nếu sau đó cấu hình cluster bị thay đổi, IForwarderHttpClientFactory sẽ chạy lại và quyết định xem có nên tạo HttpMessageInvoker mới hay tiếp tục sử dụng cái hiện có. Triển khai mặc định của IForwarderHttpClientFactory tạo một HttpMessageInvoker mới khi có thay đổi đối với HttpClientConfig.

Các thuộc tính của outgoing requests (yêu cầu đi ra) cho một cluster nhất định cũng có thể được cấu hình. Chúng được định nghĩa trong ForwarderRequestConfig.

Cấu hình được biểu diễn khác nhau tùy thuộc vào việc bạn đang sử dụng model IConfiguration hay model code-first (code ưu tiên).

IConfiguration

Các kiểu này tập trung vào việc định nghĩa cấu hình có thể serialize. Model cấu hình dựa trên code được mô tả bên dưới trong phần "Code Configuration".

HttpClient

Cấu hình HTTP client dựa trên HttpClientConfig và được biểu diễn bởi schema cấu hình sau. Nếu bạn cần cách tiếp cận chi tiết hơn, hãy sử dụng triển khai tùy chỉnh của IForwarderHttpClientFactory.

json
"HttpClient": {
  "SslProtocols": [ "<protocol-names>" ],
  "MaxConnectionsPerServer": "<int>",
  "DangerousAcceptAnyServerCertificate": "<bool>",
  "RequestHeaderEncoding": "<encoding-name>",
  "ResponseHeaderEncoding": "<encoding-name>",
  "EnableMultipleHttp2Connections": "<bool>",
  "WebProxy": {
    "Address": "<url>",
    "BypassOnLocal": "<bool>",
    "UseDefaultCredentials": "<bool>"
  }
}

Các cài đặt cấu hình:

json
"SslProtocols": [
  "Tls11",
  "Tls12"
]
json
"MaxConnectionsPerServer": "10"
json
"DangerousAcceptAnyServerCertificate": "true"
json
"RequestHeaderEncoding": "utf-8"
json
"ResponseHeaderEncoding": "utf-8"

Lưu ý rằng nếu bạn đang sử dụng mã hóa khác ngoài ASCII, bạn cũng cần cấu hình server của mình để chấp nhận yêu cầu và/hoặc gửi phản hồi với các header như vậy. Ví dụ, khi sử dụng Kestrel làm server, hãy dùng KestrelServerOptions.RequestHeaderEncodingSelector / .ResponseHeaderEncodingSelector để cấu hình Kestrel cho phép header Latin1 ("iso-8859-1"):

csharp
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel(kestrel =>
{
    kestrel.RequestHeaderEncodingSelector = _ => Encoding.Latin1;
    // và/hoặc
    kestrel.ResponseHeaderEncodingSelector = _ => Encoding.Latin1;
});
json
"EnableMultipleHttp2Connections": false
json
"WebProxy": {
  "Address": "http://myproxy:8080",
  "BypassOnLocal": "true",
  "UseDefaultCredentials": "false"
}

ForwarderHttpClientFactory mặc định đặt UseProxy thành false. Nếu bạn muốn sử dụng default system proxy (proxy hệ thống mặc định) thay vì chỉ định địa chỉ proxy tùy chỉnh, bạn có thể đặt lại UseProxy thành true bằng phương thức ConfigureHttpClient. Điều này hữu ích khi debug với các công cụ như Fiddler. Xem phần Configuring the http client để biết ví dụ.

HttpRequest

Cấu hình HTTP request dựa trên ForwarderRequestConfig và được biểu diễn bởi schema cấu hình sau.

json
"HttpRequest": {
  "ActivityTimeout": "<timespan>",
  "Version": "<string>",
  "VersionPolicy": ["RequestVersionOrLower", "RequestVersionOrHigher", "RequestVersionExact"],
  "AllowResponseBuffering": "<bool>"
}

Các cài đặt cấu hình:

Ví dụ cấu hình

Ví dụ dưới đây cho thấy 2 mẫu cấu hình HTTP client và request cho cluster1cluster2.

json
{
  "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/"
        }
      }
    }
  }
}

Code Configuration (Cấu hình bằng code)

Cấu hình HTTP client sử dụng kiểu HttpClientConfig.

Sau đây là ví dụ về HttpClientConfig sử dụng cấu hình dựa trên code. Một instance của HttpClientConfig được gán cho thuộc tính ClusterConfig.HttpClient trước khi truyền mảng cluster cho phương thức LoadFromMemory.

csharp
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);

Configuring the http client (Cấu hình http client)

ConfigureHttpClient cung cấp một callback để tùy chỉnh các cài đặt SocketsHttpHandler được sử dụng để proxy các yêu cầu. Điều này sẽ được gọi mỗi khi cluster được thêm hoặc thay đổi. Cài đặt cluster được áp dụng cho handler trước callback. Dữ liệu tùy chỉnh có thể được cung cấp trong cluster metadata. Ví dụ này cho thấy việc thêm một client certificate (chứng chỉ client) để xác thực proxy với các destination server.

csharp
var clientCert = new X509Certificate2("path");
services.AddReverseProxy()
    .ConfigureHttpClient((context, handler) =>
    {
        handler.SslOptions.ClientCertificates.Add(clientCert);
    });

Sử dụng default system proxy

ForwarderHttpClientFactory mặc định đặt UseProxy thành false để tránh overhead của việc phát hiện và cấu hình proxy. Nếu bạn cần sử dụng default system proxy (ví dụ, khi debug với Fiddler hoặc các công cụ proxy khác), bạn có thể đặt lại UseProxy thành true:

csharp
services.AddReverseProxy()
    .ConfigureHttpClient((context, handler) =>
    {
        handler.UseProxy = true;
    });

Cấu hình này cho phép HttpClient sử dụng cài đặt proxy mặc định của hệ thống mà không cần chỉ định thủ công địa chỉ proxy trong cấu hình WebProxy.

Custom IForwarderHttpClientFactory (Tùy chỉnh IForwarderHttpClientFactory)

Nếu cần kiểm soát trực tiếp việc xây dựng HTTP client, IForwarderHttpClientFactory mặc định có thể được thay thế bằng một triển khai tùy chỉnh. Đối với một số tùy chỉnh, bạn có thể kế thừa từ ForwarderHttpClientFactory mặc định và ghi đè các phương thức cấu hình client.

Nên đặt các thuộc tính SocketsHttpHandler sau đây với cùng giá trị như factory mặc định để duy trì hành vi reverse proxy đúng đắn và tránh overhead không cần thiết.

csharp
new SocketsHttpHandler
{
    UseProxy = false,
    AllowAutoRedirect = false,
    AutomaticDecompression = DecompressionMethods.None,
    UseCookies = false,
    EnableMultipleHttp2Connections = true,
    ActivityHeadersPropagator = new ReverseProxyPropagator(DistributedContextPropagator.Current),
    ConnectTimeout = TimeSpan.FromSeconds(15),
};

Luôn trả về instance HttpMessageInvoker thay vì instance HttpClient vốn kế thừa từ HttpMessageInvoker. HttpClient buffer (đệm) các phản hồi theo mặc định, điều này làm hỏng các kịch bản streaming và tăng mức sử dụng bộ nhớ và độ trễ.

Dữ liệu tùy chỉnh có thể được cung cấp trong cluster metadata.

Dưới đây là ví dụ về triển khai tùy chỉnh IForwarderHttpClientFactory.

csharp
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);
    }
}