YARP Header Based Routing (Định tuyến dựa trên Header trong YARP)
Nguồn: YARP Header Based Routing
Các proxy route (tuyến đường proxy) được chỉ định trong config hoặc qua code phải bao gồm ít nhất một path (đường dẫn) hoặc host để match (khớp). Ngoài ra, một route cũng có thể chỉ định một hoặc nhiều header phải có trong yêu cầu.
Precedence (Thứ tự ưu tiên)
Thứ tự match route mặc định là:
- path (đường dẫn)
- method (phương thức)
- host (máy chủ)
- headers (tiêu đề)
- query parameters (tham số truy vấn)
Điều đó có nghĩa là một route chỉ định methods và không có headers sẽ match trước một route chỉ định headers và không có methods. Điều này có thể được ghi đè bằng cách đặt thuộc tính Order trên một route (xem ví dụ trong config properties).
Configuration (Cấu hình)
Headers được chỉ định trong phần Match của một proxy route.
Nếu nhiều header rules được chỉ định trên một route thì tất cả phải match để route được chọn. Logic OR phải được triển khai trong một header rule hoặc dưới dạng các route riêng biệt.
Cấu hình:
"Routes": {
"route1" : {
"ClusterId": "cluster1",
"Match": {
"Path": "{**catch-all}",
"Headers": [
{
"Name": "header1",
"Values": [ "value1" ],
"Mode": "ExactHeader"
}
]
}
},
"route2" : {
"ClusterId": "cluster1",
"Match": {
"Path": "{**catch-all}",
"Headers": [
{
"Name": "header2",
"Values": [ "1prefix", "2prefix" ],
"Mode": "HeaderPrefix"
}
]
}
},
"route3" : {
"ClusterId": "cluster1",
"Match": {
"Path": "{**catch-all}",
"Headers": [
{
"Name": "header3",
"Mode": "Exists"
}
]
}
},
"route4" : {
"ClusterId": "cluster1",
"Match": {
"Path": "{**catch-all}",
"Headers": [
{
"Name": "header4",
"Values": [ "value1", "value2" ],
"Mode": "ExactHeader"
},
{
"Name": "header5",
"Mode": "Exists"
}
]
}
},
"route5" : {
"ClusterId": "cluster1",
"Match": {
"Path": "{**catch-all}",
"Headers": [
{
"Name": "header5",
"Values": [ "value1", "value2" ],
"Mode": "Contains"
},
{
"Name": "header6",
"Mode": "Exists"
}
]
}
},
"route6" : {
"ClusterId": "cluster1",
"Match": {
"Path": "{**catch-all}",
"Headers": [
{
"Name": "header6",
"Values": [ "value1", "value2" ],
"Mode": "NotContains"
},
{
"Name": "header7",
"Mode": "Exists"
}
]
}
},
"route7" : {
"ClusterId": "cluster1",
"Match": {
"Path": "{**catch-all}",
"Headers": [
{
"Name": "header7",
"Mode": "NotExists"
}
]
}
}
}Code:
var routes = new[]
{
new RouteConfig()
{
RouteId = "route1",
ClusterId = "cluster1",
Match = new RouteMatch
{
Path = "{**catch-all}",
Headers = new[]
{
new RouteHeader()
{
Name = "Header1",
Values = new[] { "value1" },
Mode = HeaderMatchMode.ExactHeader
}
}
}
},
new RouteConfig()
{
RouteId = "route2",
ClusterId = "cluster1",
Match = new RouteMatch
{
Path = "{**catch-all}",
Headers = new[]
{
new RouteHeader()
{
Name = "Header2",
Values = new[] { "1prefix", "2prefix" },
Mode = HeaderMatchMode.HeaderPrefix
}
}
}
},
new RouteConfig()
{
RouteId = "route3",
ClusterId = "cluster1",
Match = new RouteMatch
{
Path = "{**catch-all}",
Headers = new[]
{
new RouteHeader()
{
Name = "Header3",
Mode = HeaderMatchMode.Exists
}
}
}
},
new RouteConfig()
{
RouteId = "route4",
ClusterId = "cluster1",
Match = new RouteMatch
{
Path = "{**catch-all}",
Headers = new[]
{
new RouteHeader()
{
Name = "Header4",
Values = new[] { "value1", "value2" },
Mode = HeaderMatchMode.ExactHeader
},
new RouteHeader()
{
Name = "Header5",
Mode = HeaderMatchMode.Exists
}
}
}
},
new RouteConfig()
{
RouteId = "route5",
ClusterId = "cluster1",
Match = new RouteMatch
{
Path = "{**catch-all}",
Headers = new[]
{
new RouteHeader()
{
Name = "Header5",
Values = new[] { "value1", "value2" },
Mode = HeaderMatchMode.Contains
}
}
}
},
new RouteConfig()
{
RouteId = "route6",
ClusterId = "cluster1",
Match = new RouteMatch
{
Path = "{**catch-all}",
Headers = new[]
{
new RouteHeader()
{
Name = "Header6",
Values = new[] { "value1", "value2" },
Mode = HeaderMatchMode.NotContains
}
}
}
},
new RouteConfig()
{
RouteId = "route7",
ClusterId = "cluster1",
Match = new RouteMatch
{
Path = "{**catch-all}",
Headers = new[]
{
new RouteHeader()
{
Name = "Header7",
Mode = HeaderMatchMode.NotExists
}
}
}
}
};Contract (Hợp đồng)
RouteHeader định nghĩa code contract (hợp đồng code) và được ánh xạ từ cấu hình.
Name (Tên)
Tên header cần kiểm tra trong yêu cầu. Cần có giá trị không rỗng. Trường này không phân biệt chữ hoa chữ thường theo HTTP RFCs.
Values (Các giá trị)
Danh sách các giá trị có thể để tìm kiếm. Header phải match ít nhất một trong các giá trị này theo Mode được chỉ định ngoại trừ 'NotContains'. Cần ít nhất một giá trị trừ khi Mode được đặt thành Exists hoặc NotExists.
Mode (Chế độ)
HeaderMatchMode chỉ định cách match các giá trị với request header. Mặc định là ExactHeader.
- ExactHeader - Bất kỳ header nào có tên đã cho phải match hoàn toàn, tùy thuộc vào giá trị của
IsCaseSensitive. Nếu một header chứa nhiều giá trị (phân cách bằng,hoặc;), chúng sẽ được tách trước khi matching. Một cặp dấu ngoặc kép đơn cũng sẽ bị loại bỏ khỏi giá trị trước khi matching. - HeaderPrefix - Bất kỳ header nào có tên đã cho phải match bằng prefix (tiền tố), tùy thuộc vào giá trị của
IsCaseSensitive. Nếu một header chứa nhiều giá trị (phân cách bằng,hoặc;), chúng sẽ được tách trước khi matching. Một cặp dấu ngoặc kép đơn cũng sẽ bị loại bỏ khỏi giá trị trước khi matching. - Exists - Header phải tồn tại và chứa bất kỳ giá trị không rỗng nào. Nếu có nhiều header có cùng tên, rule cũng sẽ match.
- Contains - Bất kỳ header nào có tên đã cho phải chứa bất kỳ giá trị match nào, tùy thuộc vào giá trị của
IsCaseSensitive. - NotContains - Không có header nào có tên đã cho có thể chứa bất kỳ giá trị match nào, tùy thuộc vào giá trị của
IsCaseSensitive. - NotExists - Header không được tồn tại trong request.
IsCaseSensitive (Phân biệt chữ hoa/thường)
Cho biết liệu việc match giá trị có nên thực hiện phân biệt chữ hoa chữ thường hay không. Mặc định là false, không phân biệt.
Examples (Ví dụ)
Các ví dụ này sử dụng cấu hình được chỉ định ở trên.
Kịch bản 1 - Exact Header Match (Khớp header chính xác)
Một yêu cầu với header sau sẽ match route1.
Header1: Value1
Nếu một header chứa nhiều giá trị, mỗi giá trị sẽ được match riêng biệt. Yêu cầu sau sẽ match.
Header1: Value1, Value2
Tương tự nếu nhiều giá trị được tách ra trên nhiều header có cùng tên.
Header1: Value1 Header1: Value2
Một cặp dấu ngoặc kép bao quanh có thể bị loại bỏ khỏi giá trị trước khi matching. Yêu cầu sau sẽ match.
Header1: "Value1"
Nhiều cặp dấu ngoặc kép sẽ không match.
Header1: ""Value1""
Kịch bản 2 - Multiple Values (Nhiều giá trị)
Route2 định nghĩa nhiều giá trị để tìm kiếm trong header ("1prefix", "2prefix"), bất kỳ giá trị nào cũng chấp nhận được. Nó cũng chỉ định Mode là HeaderPrefix, vì vậy bất kỳ header nào bắt đầu bằng những giá trị đó đều chấp nhận được.
Bất kỳ header nào sau đây sẽ match route2.
Header2: 1prefix
Header2: 2prefix
Header2: 1prefix-extra
Header2: 2prefix-extra
Nếu một header chứa nhiều giá trị, mỗi giá trị sẽ được match riêng biệt. Yêu cầu sau sẽ match.
Header2: foo, 1prefix, 2prefix
Tương tự nếu nhiều giá trị được tách ra trên nhiều header có cùng tên.
Header2: 1prefix Header2: 2prefix
Một cặp dấu ngoặc kép bao quanh có thể bị loại bỏ khỏi giá trị trước khi matching. Yêu cầu sau sẽ match.
Header2: "2prefix"
Nhiều cặp dấu ngoặc kép sẽ không match.
Header2: ""2prefix""
Kịch bản 3 - Exists (Tồn tại)
Route3 chỉ yêu cầu header "Header3" tồn tại với bất kỳ giá trị không rỗng nào.
Sau đây là ví dụ sẽ match route3.
Header3: value
Header rỗng sẽ không match.
Header3:
Mode này hỗ trợ các header có nhiều giá trị và nhiều header có cùng tên vì nó không xem xét nội dung header. Sau đây sẽ match.
Header3: value1, value2
Header3: value1 Header3: value2
Header3: Header3:
Kịch bản 4 - Multiple Headers (Nhiều header)
Route4 yêu cầu cả header4 và header5, mỗi cái match theo Mode đã chỉ định. Các header sau sẽ match route4:
Header4: value1 Header5: AnyValue
Header4: value2 Header5: AnyValue
Những cái này sẽ không match route4 vì thiếu một trong các header yêu cầu:
Header4: value2
Header5: AnyValue
Kịch bản 5 - NotExists (Không tồn tại)
Route7 yêu cầu header "Header7" không được tồn tại.
Các header sau sẽ match route7:
NotHeader7: AnyValue
Các header sau sẽ không match route7 vì header "Header7" tồn tại.
Header7: AnyValue
Header7: