Nguon: Microsoft Learn · .NET 8.0

Các File Cấu Hình YARP

Nguồn: YARP Configuration Files

Reverse proxy có thể tải cấu hình cho các route và cluster từ file bằng cách sử dụng abstraction (lớp trừu tượng) IConfiguration từ Microsoft.Extensions.

Bài viết này cung cấp ví dụ về cấu hình proxy cho YARP. Mặc dù ví dụ cấu hình sử dụng JSON, bất kỳ nguồn IConfiguration nào cũng sẽ hoạt động. Ngoài ra, cấu hình được cập nhật mà không cần khởi động lại proxy khi file nguồn thay đổi.

Tải cấu hình proxy

Để tải cấu hình proxy từ instance (phiên bản) IConfiguration, thêm code sau vào file Program.cs:

csharp
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;

var builder = WebApplication.CreateBuilder(args);

// Thêm khả năng reverse proxy cho máy chủ
builder.Services.AddReverseProxy()
    // Khởi tạo reverse proxy từ phần "ReverseProxy" của cấu hình
    .LoadFromConfig(builder.Configuration.GetSection("ReverseProxy"));

var app = builder.Build();

// Đăng ký các route của reverse proxy
app.MapReverseProxy();

app.Run();

Để biết chi tiết về thứ tự middleware, xem ASP.NET Core Middleware > Middleware order.

Cấu hình có thể được sửa đổi trong quá trình tải bằng cách sử dụng YARP configuration filters.

Tải từ nhiều nguồn cấu hình

Bắt đầu từ phiên bản 1.1, YARP hỗ trợ tải cấu hình proxy từ nhiều nguồn. Bạn có thể gọi phương thức LoadFromConfig nhiều lần và tham chiếu các phần IConfiguration khác nhau. Bạn cũng có thể kết hợp lời gọi với một nguồn cấu hình khác, chẳng hạn như InMemory. Các route có thể tham chiếu các cluster từ các nguồn khác.

Việc hợp nhất cấu hình một phần từ các nguồn khác nhau cho một route hoặc cluster cụ thể không được hỗ trợ.

csharp
services.AddReverseProxy()
    .LoadFromConfig(Configuration.GetSection("ReverseProxy1"))
    .LoadFromConfig(Configuration.GetSection("ReverseProxy2"));

Một ví dụ khác:

csharp
services.AddReverseProxy()
    .LoadFromMemory(routes, clusters)
    .LoadFromConfig(Configuration.GetSection("ReverseProxy"));

Xem xét contract cấu hình

Cấu hình dựa trên file được ánh xạ động sang các kiểu trong namespace Yarp.ReverseProxy.Configuration bởi một implementation (triển khai) IProxyConfigProvider. Contract được chuyển đổi khi khởi động ứng dụng và mỗi khi cấu hình thay đổi.

Kiểm tra cấu trúc cấu hình

Cấu hình bao gồm một phần được đặt tên và các phần con cho các route và cluster. Trong ví dụ trước, phần được đặt tên là Configuration.GetSection("ReverseProxy").

json
{
  "ReverseProxy": {
    "Routes": {
      "route1" : {
        "ClusterId": "cluster1",
        "Match": {
          "Path": "{**catch-all}",
          "Hosts" : [ "www.aaaaa.com", "www.bbbbb.com"]
        }
      }
    },
    "Clusters": {
      "cluster1": {
        "Destinations": {
          "cluster1/destination1": {
            "Address": "https://example.com/"
          }
        }
      }
    }
  }
}

Định nghĩa các route cấu hình

Phần Routes là một tập hợp không có thứ tự các kết quả khớp route và cấu hình liên quan của chúng.

Mỗi route yêu cầu ít nhất các trường sau:

Kết quả khớp route dựa trên các route cụ thể nhất có mức ưu tiên cao nhất, như được mô tả trong URL matching. Thứ tự rõ ràng có thể được thực hiện bằng cách sử dụng trường order, trong đó các giá trị thấp hơn có mức ưu tiên cao hơn.

YARP headers, authentication and authorization (xác thực và ủy quyền), cross-origin requests (CORS) và các chính sách dựa trên route khác có thể được cấu hình trên mỗi mục nhập route. Đối với các trường khác, xem tài liệu tham khảo RouteConfig.

Proxy áp dụng các tiêu chí khớp và chính sách đã cho, và chuyển yêu cầu sang cluster được chỉ định.

Định nghĩa các cluster cấu hình

Phần Clusters là một tập hợp không có thứ tự các cluster được đặt tên. Một cluster chủ yếu chứa một tập hợp các destination (đích) được đặt tên và địa chỉ của chúng, bất kỳ đích nào trong số đó đều được coi là có khả năng xử lý các yêu cầu cho một route cụ thể. Proxy xử lý yêu cầu theo cấu hình route và cluster để chọn một destination.

Đối với các trường khác, xem tài liệu tham khảo ClusterConfig.

Xem xét tất cả các thuộc tính cấu hình

Ví dụ JSON sau đây hiển thị tất cả các thuộc tính có sẵn cho cấu hình YARP proxy.

json
{
  // Các URL cơ sở mà máy chủ lắng nghe, phải được cấu hình độc lập với các route được định nghĩa bên dưới
  "Urls": "http://localhost:5000;https://localhost:5001",
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      // Bỏ comment để ẩn các thông báo chẩn đoán từ runtime và proxy
      // "Microsoft": "Warning",
      // "Yarp" : "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "ReverseProxy": {
    // Routes thông báo cho proxy biết yêu cầu nào cần chuyển tiếp
    "Routes": {
      "minimumroute" : {
        // Khớp với bất kỳ thứ gì và route đến www.example.com
        "ClusterId": "minimumcluster",
        "Match": {
          "Path": "{**catch-all}"
        }
      },
      "allrouteprops" : {
        // Khớp với /something/* và route đến "allclusterprops"
        "ClusterId": "allclusterprops", // Tên của một cluster
        "Order" : 100, // Số thấp hơn có ưu tiên cao hơn
        "MaxRequestBodySize" : 1000000, // Tính bằng bytes. Ghi đè tùy chọn giới hạn của máy chủ (mặc định 30MB). Đặt -1 để vô hiệu hóa.
        "AuthorizationPolicy" : "Anonymous", // Tên của chính sách hoặc "Default", "Anonymous"
        "CorsPolicy" : "Default", // Tên của CorsPolicy áp dụng cho route này hoặc "Default", "Disable"
        "Match": {
          "Path": "/something/{**remainder}", // Đường dẫn để khớp sử dụng cú pháp ASP.NET
          "Hosts" : [ "www.aaaaa.com", "www.bbbbb.com"], // Tên máy chủ để khớp, không chỉ định là bất kỳ
          "Methods" : [ "GET", "PUT" ], // Các phương thức HTTP khớp, không chỉ định là tất cả
          "Headers": [ // Tiêu đề để khớp, không chỉ định là bất kỳ
            {
              "Name": "MyCustomHeader", // Tên của tiêu đề
              "Values": [ "value1", "value2", "another value" ], // Khớp với bất kỳ giá trị nào trong số này
              "Mode": "ExactHeader", // Hoặc, khớp "HeaderPrefix", "Exists", "Contains", "NotContains", "NotExists"
              "IsCaseSensitive": true
            }
          ],
          "QueryParameters": [ // Tham số query để khớp, không chỉ định là bất kỳ
            {
              "Name": "MyQueryParameter", // Tên của tham số query
              "Values": [ "value1", "value2", "another value" ], // Khớp với bất kỳ giá trị nào trong số này
              "Mode": "Exact", // Hoặc, khớp "Prefix", "Exists", "Contains", "NotContains"
              "IsCaseSensitive": true
            }
          ]
        },
        "Metadata" : { // Danh sách các cặp key-value có thể được sử dụng bởi các extension tùy chỉnh
          "MyName" : "MyValue"
        },
        "Transforms" : [ // Danh sách các transform. Xem bài viết về Transforms để biết thêm chi tiết
          {
            "RequestHeader": "MyHeader",
            "Set": "MyValue"
          }
        ]
      }
    },
    // Clusters cho proxy biết nơi và cách chuyển tiếp yêu cầu
    "Clusters": {
      "minimumcluster": {
        "Destinations": {
          "example.com": {
            "Address": "http://www.example.com/"
          }
        }
      },
      "allclusterprops": {
        "Destinations": {
          "first_destination": {
            "Address": "https://contoso.com"
          },
          "another_destination": {
            "Address": "https://10.20.30.40",
            "Health" : "https://10.20.30.40:12345/test" // Ghi đè cho kiểm tra sức khỏe chủ động
          }
        },
        "LoadBalancingPolicy" : "PowerOfTwoChoices", // Hoặc "FirstAlphabetical", "Random", "RoundRobin", "LeastRequests"
        "SessionAffinity": {
          "Enabled": true, // Mặc định là 'false'
          "Policy": "Cookie", // Mặc định, hoặc "CustomHeader"
          "FailurePolicy": "Redistribute", // Mặc định, hoặc "Return503Error"
          "Settings" : {
              "CustomHeaderName": "MySessionHeaderName" // Mặc định là 'X-Yarp-Proxy-Affinity'
          }
        },
        "HealthCheck": {
          "Active": { // Thực hiện các lời gọi API để xác thực sức khỏe
            "Enabled": "true",
            "Interval": "00:00:10",
            "Timeout": "00:00:10",
            "Policy": "ConsecutiveFailures",
            "Path": "/api/health", // Điểm cuối API để truy vấn trạng thái sức khỏe
            "Query": "?foo=bar"
          },
          "Passive": { // Vô hiệu hóa các destination dựa trên mã phản hồi HTTP
            "Enabled": true, // Mặc định là false
            "Policy" : "TransportFailureRateHealthPolicy", // Bắt buộc
            "ReactivationPeriod" : "00:00:10" // 10s
          }
        },
        "HttpClient" : { // Cấu hình của instance HttpClient được sử dụng để liên hệ với các destination
          "SSLProtocols" : "Tls13",
          "DangerousAcceptAnyServerCertificate" : false,
          "MaxConnectionsPerServer" : 1024,
          "EnableMultipleHttp2Connections" : true,
          "RequestHeaderEncoding" : "Latin1", // Cách diễn giải các ký tự không phải ASCII trong giá trị tiêu đề yêu cầu
          "ResponseHeaderEncoding" : "Latin1" // Cách diễn giải các ký tự không phải ASCII trong giá trị tiêu đề phản hồi
        },
        "HttpRequest" : { // Các tùy chọn để gửi yêu cầu đến destination
          "ActivityTimeout" : "00:02:00",
          "Version" : "2",
          "VersionPolicy" : "RequestVersionOrLower",
          "AllowResponseBuffering" : "false"
        },
        "Metadata" : { // Các cặp key-value tùy chỉnh
          "TransportFailureRateHealthPolicy.RateLimit": "0.5", // Được sử dụng bởi chính sách sức khỏe Passive
          "MyKey" : "MyValue"
        }
      }
    }
  }
}