Lingua dei criteri di instradamento per i load balancer

Informazioni su come scrivere le istruzioni delle condizioni dei criteri di instradamento che guidano il comportamento di instradamento di un load balancer.

Per controllare la modalità di instradamento delle richieste in entrata a risorse come i server Web, è necessario creare criteri. Questi criteri assumono la forma generale "Se questo, inoltra il traffico a un set backend". Il set backend deve essere uno già creato.

I criteri di instradamento funzionano nei modi riportati di seguito.

  • Ogni richiesta HTTP viene valutata in base alle regole.
  • Le regole vengono eseguite nell'ordine definito nel criterio.
  • Ogni regola dispone di almeno una condizione e di un set backend.
  • Se la condizione di richiesta HTTP corrisponde a una regola, la richiesta viene inoltrata al set backend definito per la regola. Le altre regole del criterio vengono saltate e la richiesta non viene valutata in base a tali regole.

Esempio: una regola di percorso

Di seguito è riportato un esempio di set di regole dei criteri di instradamento che contiene una sola regola basata su percorso.

{
  "name": "BasicPathBasedPolicy",
  "conditionLanguageVersion": "V1",
  "rules": [
    {
      "name": "Documents_rule",
      "condition" : "any(http.request.url.path eq (i '/documents'))",
      "actions": [{
        "name": "FORWARD_TO_BACKENDSET",
        "backendSetName": "backendSetForDocuments"
      }]
    }
  ]
}

Questo esempio mostra gli elementi riportati di seguito.

  • Il set di regole è racchiuso tra parentesi graffe { } e contiene un nome per il set di regole, il numero di versione della lingua e un nome per il set di regole.

  • Il nome del set di regole nell'esempio è "BasicPathBasedPolicy". Le regole del set sono contenute tra parentesi quadre.

  • L'unica regola del set è denominata "Documents_rule".

  • La condizione per la regola indica che se any delle condizioni viene soddisfatta, eseguire l'azione in "actions".

  • La condizione confronta il percorso dell'URL della richiesta HTTP in entrata con /documents. Il confronto è eq, ovvero uguale, che può essere scritto anche come =.

  • Nell'istruzione della condizione (i '/documents') dichiara che '/documents' non fa distinzione tra maiuscole e minuscole.

  • Quando la condizione viene soddisfatta, l'azione intrapresa consiste nell'inoltrare la richiesta a un set backend specifico, in questo caso "backendSetForDocuments". Questo set backend deve esistere affinché la regola sia valida.

È possibile analizzare la regola come "Se il percorso URL richiesto corrisponde esattamente a /documents, inoltrare la richiesta al set backend backendSetForDocuments.

Esempio: due regole di percorso semplici

Di seguito è riportato un esempio di set di regole dei criteri di instradamento che contiene due semplici regole basate su percorso. Una query in entrata viene inviata a un set backend diverso in base al percorso dell'URL della richiesta e l'inoltro viene eseguito se viene soddisfatta la prima o la seconda condizione. Nel criterio vengono valutate più regole in base al relativo ordine. Se una query corrisponde a entrambe queste condizioni, l'azione viene eseguita sulla prima corrispondente e la seconda viene saltata.

{
  "name": "PathBasedPolicy",
  "conditionLanguageVersion": "V1",
  "rules": [
    {
      "name": "Documents_rule",
      "condition" : "any(http.request.url.path eq (i '/documents'))",
      "actions": [{
        "name": "FORWARD_TO_BACKENDSET",
        "backendSetName": "backendSetForDocuments"
      }]
    },
    {
      "name": "Videos_rule",
      "condition" : "any(http.request.url.path eq (i '/videos'))",
      "actions": [{
        "name": "FORWARD_TO_BACKENDSET",
        "backendSetName": "backendSetForVideos"
      }]
    }
  ]
}

Esempio: una regola con due condizioni

Il criterio successivo contiene una regola con due condizioni (ogni condizione è separata da una virgola). La prima condizione esamina le intestazioni della richiesta e la seconda esamina la stringa di query della richiesta:

      {
        "name": "Example_policy",
        "conditionLanguageVersion": "V1",
        "rules": [
          {
            "name": "HR_mobile_user_rule",
            "condition" : "all(http.request.headers[(i 'user-agent')] eq (i 'mobile'), http.request.url.query['department'] eq 'HR')",
            "actions": [{
              "name": "FORWARD_TO_BACKENDSET",
              "backendSetName": "backendSetForHRMobileUsers"
            }]
          }
        ]
      }

La regola ora richiede che due condizioni siano entrambe vere per inoltrare una richiesta a un set backend, poiché inizia con la parola chiave all. Le condizioni per la regola possono essere parafrasate come "Se il valore user-agent richiesto nell'intestazione è impostato su mobile e il valore department nell'intestazione è HR, inoltrare al set backend specificato.

Esempio: due regole

L'ultimo esempio mostra due regole. Ogni regola ha un'azione diversa ed entrambe le regole hanno due condizioni. È importante sottolineare che la seconda regola inizia con la parola chiave any, ovvero che solo una delle due condizioni deve essere vera per attivare l'azione. Se sono specificate più di due condizioni, se una di esse è vera, l'azione viene attivata.

      {
        "name": "Example_policy",
        "conditionLanguageVersion": "V1",
        "rules": [
          {
            "name": "HR_mobile_user_rule",
            "condition" : "all(http.request.headers[(i 'user-agent')] eq (i 'mobile'), http.request.url.query['department'] eq 'HR')",
            "actions": [{
              "name": "FORWARD_TO_BACKENDSET",
              "backendSetName": "backendSetForHRMobileUsers"
            }]
          },
          {
            "name": "Documents_rule",
            "condition" : "any(http.request.url.path eq (i '/documents'), http.request.headers[(i 'host')] eq 'doc.myapp.com')",
            "actions": [{
              "name": "FORWARD_TO_BACKENDSET"
              "backendSetName": "backendSetForDocuments"
            }]
          }
        ]
      }

Condizioni regola

Le condizioni delle regole vengono scritte sotto forma di predicati. Più predicati possono essere utilizzati in una condizione, utilizzando combinatori. I due combinatori any() e all() si comportano come un OR logico o AND. Un combinatore può anche essere negato mettendo la parola chiave non prima di esso. Un semplice predicato può essere espresso come:

left value matcher right value

Una condizione per una regola che deve corrispondere se il percorso dell'URL della richiesta HTTP inizia con /foo/bar è:

http.request.url.path sw '/foo/bar'

Ulteriori dettagli sulle corrispondenze disponibili sono disponibili in Corrispondenti.

Ulteriori dettagli sulle variabili disponibili sono disponibili in Variabili.

Sintassi per più predicati

not? any|all(<condition>,<condition>,...)

Ad esempio:

all(http.request.url.path sw '/foo', 'bar' in (http.request.url.query))

Esempi di condizioni

Di seguito sono riportati altri esempi di utilizzo delle condizioni. Di seguito sono riportati ulteriori dettagli sulla sintassi e sulle funzionalità esatte.

  • Per trovare una corrispondenza con una richiesta HTTP se il relativo percorso URL inizia con /category/element:
    http.request.url.path sw '/category/element'
  • Per trovare una corrispondenza con una richiesta HTTP se il relativo percorso URL inizia con /category o termina con /id:
    any(http.request.url.path sw '/category', http.request.url.path ew '/id')
  • Per trovare una corrispondenza con una richiesta HTTP se è presente un'intestazione di richiesta User-Agent:
    (i 'User-Agent') in (http.request.headers)
  • Per trovare una corrispondenza con una richiesta HTTP se l'intestazione User-Agent ha il valore Some User Agent:
    http.request.headers[(i 'User-Agent')] eq 'Some User Agent'
  • Per trovare una corrispondenza con una richiesta HTTP se la stringa di query URL contiene una chiave con distinzione tra maiuscole e minuscole search, ad esempio come nell'URL https://www.example.com/category/?search=item+foo%20bar&page=1:
    'search' in (http.request.url.query)
  • Per trovare una corrispondenza con una richiesta HTTP se la stringa di query URL contiene una chiave con distinzione tra maiuscole e minuscole search (con distinzione tra maiuscole e minuscole) con un valore senza distinzione tra maiuscole e minuscole item+foo%20bar, ad esempio come nell'URL: https://www.domain.com/category/?search=item+foo%20bar&page=1
    http.request.url.query['search'] = (i 'item foo bar')

    La corrispondenza per la query URL (sia chiavi che valori) deve essere eseguita utilizzando le versioni non caratterizzate da URL dei relativi valori.

  • Per trovare una corrispondenza senza distinzione tra maiuscole e minuscole con una richiesta HTTP per un cookie denominato tastycookie:
    (i 'tastycookie') in (http.request.cookies)
  • Per trovare una corrispondenza senza distinzione tra maiuscole e minuscole con una richiesta HTTP per un cookie denominato tastycookie che contiene il valore con distinzione tra maiuscole e minuscole strawberry:
    http.request.cookies[(i 'tastycookie')] = 'strawberry'

Confronta

Sono disponibili più abbinamenti da utilizzare nelle condizioni.

Corrispondenti stringa

Nella tabella seguente sono elencati gli abbinamenti che operano su valori stringa. Alcuni matchers hanno varianti alternative, il che significa che una di queste varianti può essere utilizzata in modo intercambiabile per quel matcher.

Gli esempi per ogni matcher corrispondono a http.request.url.path contenente /category/element/id:

Nome Alternative descrizione; Esempio
eq =, ==, equal, equals Corrisponde se i valori sul lato sinistro e destro della corrispondenza sono uguali. http.request.url.path eq "/category/element/id"
ew Corrisponde se il valore sul lato sinistro termina con il valore sul lato destro. http.request.url.path ew '/id'
sw Corrisponde se il valore sul lato sinistro inizia con il valore sul lato destro. http.request.url.path sw '/category'
not eq !=, not equal, not equals Corrisponde se i valori sul lato sinistro e destro della corrispondenza non sono uguali. http.request.url.path neq '/some/other/path'
not ew Corrisponde se il valore sul lato sinistro non termina con il valore sul lato destro. http.request.url.path not ew '/not_id'
not sw Corrisponde se il valore sul lato sinistro non inizia con il valore sul lato destro. http.request.url.path not sw '/not_category'

Corrispondenze parziali

Alcune delle variabili utilizzate nelle regole contengono mappe chiave-valore arbitrarie di dati quando vengono eseguite le regole. Ad esempio, http.request.headers contiene le intestazioni delle richieste HTTP. Per ulteriori dettagli sulle mappe disponibili, vedere Variabili.

I corrispondenti in e not in possono essere utilizzati per verificare se una variabile di mappa contiene una chiave specifica. Dipende dalla variabile che cosa rappresenta effettivamente la chiave.

La sintassi per verificare se una variabile mappa contiene una chiave specifica è la seguente:

<key> in (<map variable>)
  • <key> deve essere una stringa con distinzione tra maiuscole e minuscole o senza distinzione tra maiuscole e minuscole.
  • Il valore del lato destro deve essere tra parentesi.

Ad esempio, questa condizione corrisponde se la richiesta HTTP dispone di un cookie denominato Foo:

'Foo' in (http.request.cookies)

Valori

I valori utilizzati nei predicati possono essere valori costanti o variabili valutate in fase di esecuzione.

Costanti

Le regole supportano le costanti stringa scritte tra virgolette singole.

Ad esempio:

http.request.url.path sw '/foo'

Maiuscole/minuscole stringa

Per impostazione predefinita, la corrispondenza delle stringhe utilizza confronti con distinzione tra maiuscole e minuscole.

Ad esempio, se il percorso dell'URL della richiesta HTTP per una richiesta è /foo, il predicato seguente non corrisponde alla richiesta, poiché viene utilizzato il confronto di stringhe con distinzione tra maiuscole e minuscole:

http.request.url.path eq '/FOO'

La corrispondenza senza distinzione tra maiuscole e minuscole viene eseguita se almeno uno dei valori confrontati è una stringa senza distinzione tra maiuscole e minuscole. La sintassi per una stringa senza distinzione tra maiuscole e minuscole è la seguente:

(i '<string content>')

Ad esempio, queste stringhe non fanno distinzione tra maiuscole e minuscole e sono pertanto equivalenti se utilizzate nei predicati:

(i 'foo')
(i 'Foo')
(i 'FOO')

Rispetto all'esempio originale, questo predicato corrisponde perché utilizza un confronto senza distinzione tra maiuscole e minuscole:

http.request.url.path eq (i '/FOO')

Stringa con distinzione tra maiuscole e minuscole

Per impostazione predefinita, la corrispondenza delle stringhe utilizza confronti con distinzione tra maiuscole e minuscole.

Ad esempio, se il percorso dell'URL di richiesta HTTP per alcune richieste è /foo, il predicato seguente non corrisponderà per tale richiesta, poiché viene utilizzato il confronto tra stringhe con distinzione tra maiuscole e minuscole:

http.request.url.path eq '/FOO'

La corrispondenza senza distinzione tra maiuscole e minuscole viene eseguita se almeno uno dei valori confrontati è una stringa senza distinzione tra maiuscole e minuscole. La sintassi di una stringa senza distinzione tra maiuscole e minuscole è la seguente:

(i '<string content>')

Ad esempio, queste stringhe non fanno distinzione tra maiuscole e minuscole e sono pertanto uguali se utilizzate nei predicati:

(i 'foo')
(i 'Foo')
(i 'FOO')

Rispetto all'esempio originale, questo predicato corrisponde perché utilizza un confronto senza distinzione tra maiuscole e minuscole:

http.request.url.path eq (i '/FOO')

Variabili

Le variabili vengono utilizzate nelle condizioni per la corrispondenza con un determinato valore della richiesta HTTP. I valori effettivi per ogni variabile vengono decisi quando vengono eseguite le regole, durante ogni singola richiesta HTTP.

Variabili tipo di mappa

Alcune variabili contengono mappe chiave-valore arbitrarie dei dati di richiesta, ad esempio intestazioni di richiesta o cookie. Per ogni chiave, possono esistere uno o più valori. Ad esempio, possono esistere diverse intestazioni di richiesta con lo stesso nome.

In genere, le variabili di mapping possono essere utilizzate nelle regole nei modi riportati di seguito.

  • Verificare se una mappa ha una chiave specifica.
  • Verificare se una mappa dispone di una chiave specifica con un valore specifico.

Verifica se una mappa ha una chiave specifica:

Controllare se una variabile mappa dispone di una chiave specifica viene eseguita con il matcher in. Per ulteriori dettagli, vedere Lingua dei criteri di instradamento per i load balancer.

Ad esempio:

'Foo' in (http.request.cookies)

Questa condizione corrisponde se la richiesta HTTP dispone di un cookie denominato Foo.

Verifica della presenza di una chiave specifica per una mappa con un valore specifico:

Controllare se una mappa dispone di una chiave specifica con un valore specifico viene eseguita utilizzando la notazione parentesi [] per ottenere i valori in una chiave specifica. La sintassi per l'utilizzo della notazione parentesi è:

<variable>[<key>]

Il valore <key> deve essere specificato come stringa con distinzione tra maiuscole e minuscole o senza distinzione tra maiuscole e minuscole.

Il controllo effettivo di un valore specifico viene eseguito utilizzando il corrispondente eq per verificare se any dei valori in tale chiave sono uguali a tale valore specifico. Il predicato corrisponde se almeno uno dei valori di tale chiave corrisponde a quel valore specifico.

Esempi:

  • Per trovare una corrispondenza se un valore qualsiasi dell'intestazione header-name è uguale a header-value:
    http.request.headers[(i 'header-name')] eq 'header-value'

    L'intestazione name viene confrontata caso per caso, ma l'intestazione value viene confrontata caso per caso.

  • Per abbinare se qualsiasi valore del cookie "nome-cookie" è uguale a cookie-value:
    http.request.cookies['cookie-name'] eq 'cookie-value'

Il programma di corrispondenza not eq può essere utilizzato per verificare che none dei valori in tale chiave siano uguali a un valore specifico.

Esempi:

  • Per trovare una corrispondenza se nessun valore dell'intestazione header-name è uguale a header-value:
    http.request.headers[(i 'header-name')] not eq 'header-value'

    Il nome dell'intestazione viene confrontato senza distinzione tra maiuscole e minuscole. Il valore dell'intestazione viene confrontato con distinzione tra maiuscole e minuscole.

  • Per corrispondere se nessun valore del cookie "cookie-name" è uguale a cookie-value:
    http.request.cookies['cookie-name'] not eq 'cookie-value'

Tutte le variabili disponibili

Le variabili disponibili per essere utilizzate nelle condizioni sono:

Nome descrizione; Esempio
http.request.headers Mappa contenente le intestazioni delle richieste HTTP.

Questa mappa presenta alcuni comportamenti speciali: le chiavi (nomi delle intestazioni) devono non fare distinzione tra maiuscole e minuscole. L'utilizzo di stringhe con distinzione tra maiuscole e minuscole per le chiavi http.request.headers nei predicati non è consentito.

  • Uso corretto:
    (i 'User-Agent') in http.request.headers
    http.request.headers[(i 'User-Agent')] = 'Mobile'
  • Uso errato:
    'User-Agent' in http.request.headers
    http.request.headers['User-Agent'] = 'Foo'
http.request.url.path Percorso URL richiesta HTTP. Questo è l'URL della richiesta, senza protocollo, dominio, porta e stringa di query.
http.request.url.query Mappa contenente gli elementi di query URL richiesta HTTP. Se l'URL della richiesta non contiene una query (non ha il carattere ?) o se la query è vuota (il carattere ? è l'ultimo nell'URL), questa mappa è vuota.

La query viene analizzata per produrre la mappa http.request.url.query, prendendo la stringa di query parte dell'URL (che è la parte dopo il primo carattere ?) e suddividendola in coppie chiave-valore, trattando questi caratteri come speciali:

  • Il carattere & è il separatore tra diverse coppie chiave-valore
  • Il carattere = è il separatore tra la chiave e il valore (all'interno di una coppia chiave-valore)

Il primo carattere ? presente nell'URL contrassegna l'inizio della stringa di query. Se dopo il primo vengono visualizzati altri ? caratteri, questi vengono trattati come qualsiasi altro carattere, senza alcuna gestione speciale.

All'interno di una coppia chiave-valore, il primo carattere = presente separa la chiave dal valore. Se sono presenti altri caratteri =, vengono considerati come parte del valore.

Le chiavi e i valori non vengono escape in base alle regole di escape URL.

URL:https://www.domain.com/path?key=value&key=%61&another%20key=another+value

I dati http.request.url.query per una richiesta con questo URL sono simili a quelli espressi come JSON:

{
  "key": [
    "value",
    "a"
  ],
  "another key": [
    "another value"
  ],
}

In questo esempio, sia la chiave che il valore vengono abbinati con distinzione tra maiuscole e minuscole. Pertanto, se invece di key=value l'URL conteneva KEY=value o key=VALUE, la condizione non corrisponde.

Tuttavia, una coppia chiave-valore della stringa di query URL non viene aggiunta alla mappa http.request.url.query nei seguenti casi:

  • Se un carattere = non è presente in una coppia chiave-valore

    Ad esempio:

    URL: https://www.example.com/path?no_key"

    In questo caso, l'elemento stringa di query no_key non è presente nella mappa http.request.url.query.

  • Se il lato sinistro del carattere = è vuoto (la chiave non viene specificata)

    Esempio: URL: https://www.domain.com/path?=no_value

    In questo caso, l'elemento stringa di query no_value non è presente nella mappa http.request.url.query.

Se il lato destro del carattere = è vuoto, il valore della coppia chiave-valore è una stringa vuota ''.

http.request.cookies

Mappa contenente i cookie di richiesta HTTP, analizzata dall'intestazione della richiesta "Cookie" come richiamato in RFC-6265, in cui la chiave è un nome cookie e il valore è il valore cookie corrispondente. Se l'intestazione della richiesta "Cookie" non è presente nella richiesta, questa mappa è vuota.

Esempi

Una richiesta HTTP/1.1 in entrata è simile a questa (riga di richiesta e intestazioni):

GET /category/some_category?action=search&query=search+terms&filters[]=5&features[]=12 HTTP/1.1
Accept-Encoding: gzip, deflate, br
Cookie: cookie_a=1; cookie_b=foo
Host: www.domain.com
User-Agent: Browser Foo/1.0
X-Forwarded-For: 1.2.3.4, 5.6.7.8
X-Forwarded-For: 9.10.11.12

Le variabili disponibili per le regole verranno quindi popolate con i dati di questa richiesta nel modo seguente: (i dati per le variabili strutturate vengono visualizzati in formato JSON)

http.request.url.path: "/category/some_category"
 
http.request.url.query: {
  "action": ["search"],
  "query": ["search terms"],
  "filters[]": ["5", "12"]
}
 
http.request.headers: {
  "Accept-Encoding": ["gzip, deflate, br"],
  "Cookie": ["some_cookie=1; another_cookie=foo"],
  "Host": ["www.domain.com"],
  "User-Agent": ["Browser Foo/1.0"],
  "X-Forwarded-For": ["1.2.3.4, 5.6.7.8", "9.10.11.12"]
}
 
http.request.cookies: {
  "cookie_a": ["1"],
  "cookie_b": ["foo"]
}

Ecco alcuni esempi di come possiamo soddisfare questa richiesta:

  • Se si desidera abbinare le richieste al dominio www.domain.com e ai percorsi URL che iniziano con /category/, utilizzare una condizione simile alla seguente:
    all(http.request.headers[(i 'Host')] eq 'www.domain.com', http.request.url.path sw '/category')
  • Per soddisfare le richieste in cui il percorso URL è esattamente /category/some_category o l'elemento query di richiesta action=search:
    any(http.request.url.path eq '/category/some_category', http.request.url.query['action'] eq 'search')
  • Per abbinare le richieste con un elemento stringa di query denominato query con valore search terms (dopo l'annullamento dell'escaping dell'URL):
    http.request.url.query['query'] eq 'search terms'
  • Per abbinare le richieste che hanno cookie cookie_a ma non hanno cookie cookie_c:
    all('cookie_a' in (http.request.cookies), 'cookie_c' not in (http.request.cookies))