Condividi tramite


Routing basato sull'intestazione di YARP

Le rotte proxy specificate in config o tramite codice devono includere almeno un path o un host a cui corrispondere. Oltre a questi, una route può anche specificare una o più intestazioni che devono essere incluse nella richiesta.

Precedenza

L'ordine di precedenza della corrispondenza del percorso predefinito è

  1. sentiero
  2. metodo
  3. padrone di casa
  4. Intestazioni
  5. parametri della query

Ciò significa che un percorso che specifica i metodi e nessuna intestazione corrisponderà prima di un percorso che specifica le intestazioni e nessun metodo. È possibile sovrascrivere impostando la proprietà Order su un percorso (vedere l'esempio nelle proprietà di configurazione ).

Configurazione

Le intestazioni sono specificate nella sezione Match di un percorso proxy.

Se su un percorso vengono specificate più regole di intestazione, tutte devono corrispondere affinché il percorso venga intrapreso. La logica OR deve essere implementata all'interno di una regola di intestazione o come percorsi separati.

Configurazione:

"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"
        }
      ]
    }
  }
}

Codice:

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

Contratto

RouteHeader definisce il contratto di codice e viene mappato dalla configurazione.

Nome

Nome dell'intestazione da verificare nella richiesta. È necessario un valore non vuoto. Questo campo non fa distinzione tra maiuscole e minuscole per le RFC HTTP.

Valori

Elenco di valori possibili da cercare. L'intestazione deve corrispondere ad almeno uno di questi valori in base al Mode specificato, ad eccezione di 'NotContains'. È necessario almeno un valore, a meno che Mode non sia impostato su Exists o NotExists.

Modalità

HeaderMatchMode specifica come trovare una corrispondenza tra i valori e l'intestazione della richiesta. Il valore predefinito è ExactHeader.

  • ExactHeader: qualsiasi intestazione con il nome specificato deve corrispondere completamente, in base al valore di IsCaseSensitive. Se un'intestazione contiene più valori (separati da , o ;), vengono suddivisi prima di effettuare il confronto. Anche una singola coppia di virgolette verrà rimossa dal valore prima della corrispondenza.
  • HeaderPrefix: qualsiasi intestazione con il nome specificato deve corrispondere al prefisso, soggetto al valore di IsCaseSensitive. Se un'intestazione contiene più valori (separati da , o ;), vengono suddivisi prima di effettuare il confronto. Anche una singola coppia di virgolette verrà rimossa dal valore prima della corrispondenza.
  • Exists: l'intestazione deve esistere e contenere qualsiasi valore non vuoto. Se sono presenti più intestazioni con lo stesso nome, allora la regola si applicherà.
  • Contiene: qualsiasi intestazione con il nome specificato deve contenere uno dei valori di corrispondenza, soggetto al valore di IsCaseSensitive.
  • NotContains: nessuna delle intestazioni con il nome dato può contenere alcun valore di corrispondenza, in conformità al valore di IsCaseSensitive.

È CaseSensitive

Indica se la corrispondenza del valore deve essere eseguita con distinzione tra maiuscole e minuscole oppure senza. Il valore predefinito è false, insensibile.

Esempi

Questi esempi usano la configurazione specificata in precedenza.

Scenario 1 - Corrispondenza esatta dell'intestazione

Una richiesta con l'intestazione seguente corrisponderà a route1.

Header1: Value1

Se un'intestazione contiene più valori, ognuno verrà confrontato separatamente. La richiesta seguente corrisponderà.

Header1: Value1, Value2

Lo stesso vale se più valori vengono suddivisi tra più intestazioni con lo stesso nome.

Header1: Value1
Header1: Value2

Una singola coppia di virgolette esterne può essere rimossa dal valore prima della corrispondenza. La richiesta seguente corrisponderà.

Header1: "Value1"

Più coppie di virgolette non corrisponderanno.

Header1: ""Value1""

Scenario 2 - Più valori

Route2 ha definito più valori da cercare in un'intestazione ("1prefix", "2prefix"), tutti i valori sono accettabili. È stato inoltre specificato il Mode come HeaderPrefix, in modo che qualsiasi intestazione che inizia con tali valori sia accettabile.

Qualsiasi delle seguenti intestazioni corrisponderà a route2.

Header2: 1prefix
Header2: 2prefix
Header2: 1prefix-extra
Header2: 2prefix-extra

Se un'intestazione contiene più valori, ognuno verrà confrontato separatamente. La seguente richiesta soddisferà i criteri.

Header2: foo, 1prefix, 2prefix

Lo stesso vale se più valori vengono suddivisi tra più intestazioni con lo stesso nome.

Header2: 1prefix
Header2: 2prefix

Una singola coppia di virgolette di chiusura può essere eliminata dal valore prima di effettuare la corrispondenza. La richiesta seguente soddisferà i criteri.

Header2: "2prefix"

Più coppie di virgolette non corrisponderanno.

Header2: ""2prefix""

Scenario 3 - Esiste

Route3 richiede solo che l'intestazione "Header3" esista con qualsiasi valore non vuoto

Di seguito è riportato un esempio che corrisponderà a route3.

Header3: value

Un'intestazione vuota non corrisponderà .

Header3:

Questa modalità supporta le intestazioni con più valori e più intestazioni con lo stesso nome perché non esamina il contenuto dell'intestazione. Il codice seguente corrisponderà.

Header3: value1, value2
Header3: value1
Header3: value2
Header3:
Header3:

Scenario 4 - Intestazioni multiple

Route4 richiede sia header4 che header5, ognuno dei quali corrisponde in base al Modespecificato. Le seguenti intestazioni corrisponderanno a route4:

Header4: value1
Header5: AnyValue
Header4: value2
Header5: AnyValue

Questi non corrisponderanno a route4 perché mancano una delle intestazioni necessarie.

Header4: value2
Header5: AnyValue

Scenario 5 - NotExists

Route7 richiede che l'intestazione "Header7" non esista

Le seguenti header corrisponderanno a route7:

NotHeader7: AnyValue

Le seguenti intestazioni non corrisponderanno a route7 perché l'intestazione "Header7" è presente.

Header7: AnyValue
Header7: