Lenguaje de política de enrutamiento para equilibradores de carga

Descubra cómo escribir sentencias de condición de política de enrutamiento que guíen el comportamiento de enrutamiento de un equilibrador de carga.

Para controlar cómo se enrutan las solicitudes entrantes a recursos como los servidores web, debe crear políticas. Estas políticas tienen el formato general "Si se da esta condición, se reenvía el tráfico a un juego de backends". El juego de backends debe ser uno que ya haya creado.

Las políticas de enrutamiento funcionan de las siguientes formas:

  • Cada solicitud HTTP se evalúa con respecto a las reglas.
  • Las reglas se ejecutan en el orden definido en la política.
  • Cada regla tiene al menos una condición y un juego de backends.
  • Si la condición de solicitud HTTP coincide con una regla, la solicitud se reenvía al juego de backends definido para la regla. Las demás reglas de la política se omiten y la solicitud no se evalúa con respecto a ellas.

Ejemplo: una regla de ruta

A continuación, se muestra un ejemplo de un juego de reglas de política de enrutamiento que contiene solo una regla basada en ruta de acceso:

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

En este ejemplo se muestran los siguientes elementos:

  • El juego de reglas está delimitado entre corchetes { } y contiene un nombre para el juego de reglas, el número de versión de lenguaje y un nombre para el juego de reglas.

  • El nombre del juego de reglas del ejemplo es "BasicPathBasedPolicy". Las reglas del juego se incluyen entre corchetes.

  • La única regla del juego se denomina "Documents_rule".

  • La condición de la regla indica que si se cumple any de las condiciones, se realice la acción de "actions".

  • La condición compara la ruta de acceso de la URL de solicitud HTTP entrante con /documents. La comparación es eq, que significa "igual que", y que también se puede escribir como =.

  • En la sentencia de condición (i '/documents') declara que '/documents' no es sensible a mayúsculas/minúsculas.

  • Cuando se cumple la condición, la acción realizada es reenviar la solicitud a un juego de backends específico, en este caso "backendSetForDocuments". Este juego de backends debe existir para que la regla sea válida.

La regla se puede parafrasear como "Si la ruta de acceso de URL solicitada es una coincidencia exacta para /documents, se reenvía la solicitud al juego de backends backendSetForDocuments.

Ejemplo: dos reglas de ruta de acceso simple

A continuación, se muestra un ejemplo de un juego de reglas de política de enrutamiento que contiene dos reglas basadas en ruta de acceso simple. Una consulta entrante se envía a un juego de backends diferente según la ruta de acceso de URL de solicitud, y el reenvío se produce si se cumple la primera condición o la segunda condición. Se evalúan varias reglas según su orden en la política. Si una consulta coincide con ambas condiciones, la acción se realiza en la primera coincidencia y se omite la segunda coincidencia.

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

Ejemplo: una regla con dos condiciones

La siguiente política tiene una regla con dos condiciones (cada condición está separada por una coma). La primera condición examina las cabeceras de solicitud y la segunda condición examina la cadena de consulta de la solicitud:

      {
        "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 regla ahora requiere que dos condiciones sean verdaderas para reenviar una solicitud a un juego de backends, ya que comienza con la palabra clave all. Las condiciones de la regla se pueden parafrasear como "Si el valor de user-agent solicitado de la cabecera está definido en mobile y el valor de department de la cabecera es HR, se reenvía al juego de backends especificado.

Ejemplo: dos reglas

El ejemplo final muestra dos reglas. Cada regla tiene una acción diferente y ambas reglas tienen dos condiciones. Es importante destacar que la segunda regla comienza con la palabra clave any, lo que significa que solo una de las dos condiciones debe ser verdadera para disparar la acción. Si se especifican más de dos condiciones, si alguna de ellas es verdadera, se dispara la acción.

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

Condiciones de regla

Las condiciones de regla se escriben en forma de predicados. Se pueden utilizar varios predicados en una condición, utilizando combinadores. Los dos combinadores: any() y all() se comportan como un OR o AND lógico. Un combinador también se puede negar colocando la palabra clave no delante. Un predicado simple se puede expresar como:

left value matcher right value

Una condición para una regla que debe coincidir si la ruta /foo/bar de la URL de solicitud HTTP empieza por:

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

Para obtener más información sobre los buscadores de coincidencias disponibles, consulte la sección Buscadores de coincidencias.

Para obtener más información sobre las variables disponibles, consulte Variables.

Sintaxis para varios predicados

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

Por ejemplo:

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

Ejemplos de condición

A continuación, se muestran más ejemplos de cómo se pueden utilizar las condiciones. A continuación, se incluyen más detalles sobre la sintaxis y las funcionalidad exactas.

  • Para hacer coincidir una solicitud HTTP si su ruta del acceso de URL empieza por /category/element:
    http.request.url.path sw '/category/element'
  • Para hacer coincidir una solicitud HTTP si su ruta de acceso de URL empieza por /category o termina por /id:
    any(http.request.url.path sw '/category', http.request.url.path ew '/id')
  • Para hacer coincidir una solicitud HTTP si existe una cabecera User-Agent de solicitud:
    (i 'User-Agent') in (http.request.headers)
  • Para hacer coincidir una solicitud HTTP si la cabecera User-Agent tiene el valor Some User Agent:
    http.request.headers[(i 'User-Agent')] eq 'Some User Agent'
  • Para hacer coincidir una solicitud HTTP si la cadena del URL de consulta tiene una clave sensible a mayúsculas/minúsculas search, por ejemplo, como en la URL https://www.example.com/category/?search=item+foo%20bar&page=1:
    'search' in (http.request.url.query)
  • Para hacer coincidir una solicitud HTTP si la cadenas de consulta de URL tiene una clave sensible a mayúsculas/minúscula search (de forma sensitiva a mayúsculas/minúscula) con un valor no sensible a mayúsculas/minúscula item+foo%20bar, por ejemplo, como en la URL: https://www.domain.com/category/?search=item+foo%20bar&page=1
    http.request.url.query['search'] = (i 'item foo bar')

    La coincidencia para la consulta de URL (tanto claves como valores) se debe realizar mediante versiones de escape de la URL de sus valores.

  • Para hacer coincidir de forma no sensible a mayúsculas/minúsculas una solicitud HTTP de una cookie denominada tastycookie:
    (i 'tastycookie') in (http.request.cookies)
  • Para hacer coincidir de forma no sensata a mayúsculas/minúscula una solicitud HTTP de una cookie denominada tastycookie que contenga el valor sensible a mayúsculas/minúscula strawberry:
    http.request.cookies[(i 'tastycookie')] = 'strawberry'

Buscadores de coincidencias

Hay varios buscadores de coincidencias disponibles para usarlos en las condiciones.

Buscadores de coincidencias de cadena

En la siguiente tabla se muestran los buscadores de coincidencias que operan en valores de cadena. Algunos buscadores de coincidencias tienen variantes alternativas, lo que significa que cualquiera de esas variantes se puede utilizar indistintamente para ese buscador de coincidencias.

Los ejemplos de cada buscador de coincidencias coinciden todos con http.request.url.path que contiene /category/element/id:

Nombre Alternativas Descripción Ejemplo
eq =, ==, equal, equals Coincide si los valores de la parte izquierda y derecha del buscador de coincidencias son iguales. http.request.url.path eq "/category/element/id"
ew Coincide si el valor de la parte izquierda termina con el valor de la parte derecha. http.request.url.path ew '/id'
sw Coincide si el valor de la parte izquierda comienza con el valor de la parte derecha. http.request.url.path sw '/category'
not eq !=, not equal, not equals Coincide si los valores de la parte izquierda y de la parte derecha del buscador de coincidencias no son iguales. http.request.url.path neq '/some/other/path'
not ew Coincide si el valor de la parte izquierda no termina con el valor de la parte derecha. http.request.url.path not ew '/not_id'
not sw Coincide si el valor de la parte izquierda no empieza por el valor de la parte derecha. http.request.url.path not sw '/not_category'

Buscadores de coincidencias parciales

Algunas de las variables utilizadas en las reglas contienen asignaciones arbitrarias clave-valor de datos cuando se ejecutan las reglas. Por ejemplo, http.request.headers contiene las Cabeceras de solicitud HTTP. Para obtener más detalles sobre las asignaciones disponibles, consulte Variables.

Los buscadores de coincidencias in y not in se pueden utilizar para comprobar si una variable que contiene una clave específica. Depende de la variable los que realmente representa la clave.

La sintaxis para comprobar si una variable de asignación contiene una clave específica es:

<key> in (<map variable>)
  • <key> debe ser una cadena sensibles a mayúsculas/minúsculas o no sensibles a mayúsculas/minúsculas.
  • El valor de la parte derecha debe estar entre paréntesis.

Por ejemplo, esta condición coincide si la solicitud HTTP tiene una cookie con el nombre Foo:

'Foo' in (http.request.cookies)

Valores

Los valores que se utilizan en los predicados pueden ser valores constantes o variables que se evalúan en tiempo de ejecución.

Constantes

Las reglas soportan constantes de cadena escritas entre comillas simples.

Ejemplo:

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

Cadenas sensibles a mayúsculas/minúsculas

La coincidencia de cadenas utiliza comparaciones sensibles a mayúsculas/minúsculas por defecto.

Por ejemplo, si la ruta de acceso de la URL de solicitud HTTP para alguna solicitud es /foo, el siguiente predicado no coincidiría con esa solicitud, ya que se utiliza la comparación de cadenas sensible a mayúsculas/minúsculas:

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

La coincidencia no sensible a mayúsculas/minúsculas se realiza si al menos uno de los valores comparados es una cadena no sensible a mayúsculas/minúsculas. La sintaxis de una cadena no sensible a mayúsculas/minúsculas es la siguiente:

(i '<string content>')

Por ejemplo, todas estas cadenas no son sensibles a mayúsculas/minúsculas y, por lo tanto, son equivalentes cuando se utilizan en predicados:

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

En comparación con el ejemplo original, este predicado coincide, ya que utiliza una comparación no sensible a mayúsculas/minúsculas:

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

Cadenas sensibles a mayúsculas/minutas

La coincidencia de cadenas utiliza comparaciones sensibles a mayúsculas/minúsculas por defecto.

Por ejemplo, si la ruta de acceso de dirección URL para alguna solicitud HTTP es /foo, el siguiente predicado no coincidiría para esa solicitud, porque se utiliza una comparación de las cadenas sensibles a mayúsculas/minugas:

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

La coincidencia no sensible a mayúsculas/minúsculas se realiza si al menos uno de los valores comparados es una cadena no sensible a mayúsculas/minúsculas. La sintaxis de una cadena no sensible a mayúsculas/minúsculas es la siguiente:

(i '<string content>')

Por ejemplo, todas estas cadenas no distinguen entre mayúsculas/minúsculas y, por lo tanto, son iguales cuando se utilizan en predicados:

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

En comparación, con el ejemplo original, este predicado coincide, ya que utiliza una comparación no sensata a mayúsculas/minúsculas:

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

Variables

Las variables se utilizan en las condiciones para coincidir con algún valor concreto de la solicitud HTTP. Los valores reales de cada variable se deciden cuando se ejecutan las reglas, durante cada solicitud HTTP individual.

Variables de tipo de asignación

Algunas de sus variables contienen asignaciones arbitrarias clave-valor para datos de solicitud, por ejemplo, cabeceras o cookies de solicitud. Para cada clave, puede haber uno o más valores. Por ejemplo, puede haber varios encabezados de solicitud con el mismo nombre.

Normalmente, las variables de asignación se pueden utilizar en las reglas de las siguientes maneras:

  • Para comprobar si una asignación tiene una clave específica.
  • Para comprobar si una asignación tiene una clave específica con un valor específico.

Comprobación de si una asignación tiene una clave específica:

La comprobación de si una variable con asignación tiene una clave específica se realiza con el explorador de coincidencias in. Para obtener más información, consulte Lenguaje de política de enrutamiento para equilibradores de carga.

Por ejemplo:

'Foo' in (http.request.cookies)

Esta condición coincide si la solicitud HTTP tiene una cookie con el nombre Foo.

Comprobación de si una asignación tiene una clave específica con un valor específico:

La comprobación de si una asignación tiene una clave específica con un valor específico se realiza mediante una notación de corchetes [] para obtener los valores en una clave específica. La sintaxis para utilizar la notación de corchetes es la siguiente:

<variable>[<key>]

<key> se debe especificar como una cadena sensata a mayúsculas/minúsculas o no sensibles a mayúsculas/minúsculas.

La comprobación real de un valor específico se realiza mediante el buscador para coincidencias eq para comprobar si any de los valores en esa clave son iguales a ese valor específico. El predicado coincide si al menos uno de los valores de esa clave coincide con ese valor específico.

Ejemplos:

  • Para obtener una coincidencia si algún valor de la cabecera header-name es igual a header-value:
    http.request.headers[(i 'header-name')] eq 'header-value'

    La cabecera name se compara de manera no sensible a mayúsculas/minutas, pero el encabezado value se compara de manera sensible a mayúsculas/minutas.

  • Para obtener una coincidencia de si algún valor de la cookie "cookie-name" es igual a cookie-value:
    http.request.cookies['cookie-name'] eq 'cookie-value'

El Buscador de coincidencias not eq se puede utilizar para comprobar que none de los valores en esa clave es igual a un valor específico.

Ejemplos:

  • Para obtener una coincidencia si ningún valor de la cabecera header-name es igual a header-value:
    http.request.headers[(i 'header-name')] not eq 'header-value'

    El nombre de cabecera se compara de forma no sensible a mayúsculas/minúsculas. El valor de cabecera se compara de forma sensible a mayúsculas/minúsculas.

  • Para obtener una coincidencia de si ningún valor de la cookie "cookie-name" es igual a cookie-value:
    http.request.cookies['cookie-name'] not eq 'cookie-value'

Todas las variables disponibles

Las variables disponibles para su uso en las condiciones son:

Nombre Descripción Ejemplo
http.request.headers Asignación que contiene cabeceras de solicitud HTTP.

Esta asignación mapa tiene algún comportamiento especial: las claves (nombres de cabeceras) deben ser cadenas sensibles a mayúsculas/minúsculas. No está permitido el uso de cadenas sensibles a mayúsculas/minúsculas para claves http.request.headers en predicados.

  • Uso correcto:
    (i 'User-Agent') in http.request.headers
    http.request.headers[(i 'User-Agent')] = 'Mobile'
  • Uso incorrecto:
    'User-Agent' in http.request.headers
    http.request.headers['User-Agent'] = 'Foo'
http.request.url.path Ruta de acceso de la URL de solicitud HTTP. Esta es la URL de solicitud, sin protocolo, dominio, puerto ni cadena de consulta.
http.request.url.query Asignación que contiene elementos de consulta de la URL de solicitud HTTP. Si la URL de solicitud No tiene una consulta (no tiene ? carácter) o si la consulta está vacía (el carácter ? es el último en la URL), esta asignación está vacía.

La consulta se analiza para producir la asignación de http.request.url.query. Para ello, se toma la parte de la Cadena de Consulta de la URL (que es la parte posterior al primer carácter ?) y se dividen en pares clave-valor, tratando estos caracteres como especiales:

  • El carácter & es el separador entre diferentes pares clave-valor
  • El carácter = es el separador entre la clave y el valor (dentro del par clave-valor)

El primer carácter ? presente en la URL marca el principio de la cadena para consulta. Si aparecen caracteres ? adicionales después del primero, se tratan del mismo forma que cualquier otro carácter, sin ninguna manipulación especial.

Dentro del par clave-valor, el primer carácter = presente separa la clave del valor. Si hay caracteres = adicionales presentes, se tratan como parte del valor.

Las claves y los valores no están identificados según las reglas de escape de URL.

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

Los datos de http.request.url.query para una solicitud con esta URL tendrían la siguiente apariencia expresada como JSON:

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

En este ejemplo, tanto la clave como el valor coinciden de forma sensible a mayúsculas/minúsculas. Por lo tanto, si en lugar de key=value, la URL tuviera KEY=value o key=VALUE, la condición no coincidiría.

Sin embargo, un par clave-valor de la cadena del consultor de URL no es agregado a la asignación de http.request.url.query en estos casos:

  • Si un carácter = no se encuentra en un par clave-valor

    Ejemplo:

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

    En este caso, el elemento no_key de cadena de consulta no está presente en la asignación de http.request.url.query.

  • Si el lado izquierdo del carácter = está vacío (la clave no está especificada).

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

    En este caso, el elemento no_value de cadena de consulta no está presente en la asignación de http.request.url.query.

Si el lado derecho del carácter = está vacío, el valor de ese par clave-valor es una cadena vacía ''.

http.request.cookies

Asignación que incluye cookies de solicitud HTTP, analizadas desde la cabecera "Cookie", como se indica en RFC-6265, donde la clave es un nombre y el valor es el valor correspondiente. Si la cabecera de solicitud "Cookie" no se encuentra en la solicitud, esta asignación está vacía.

Ejemplos

Una solicitud HTTP/1.1 entrante tiene este aspecto (línea de solicitud y cabeceras):

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

Posteriormente, las variables disponibles para las reglas se rellenarán con datos de esta solicitud de la siguiente forma: (los datos de las variables estructuradas se muestran en 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"]
}

A continuación, se muestran algunos ejemplos de cómo podemos hacer coincidir esta solicitud:

  • Si quisiéramos hacer coincidir las solicitudes con el dominio www.domain.com y las rutas de URL que empiezan por /category/, utilizaríamos una condición como esta:
    all(http.request.headers[(i 'Host')] eq 'www.domain.com', http.request.url.path sw '/category')
  • Para hacer coincidir solicitudes en la que la ruta de Acceso de la URL es exactamente /category/some_category o el elemento de consulta action=search:
    any(http.request.url.path eq '/category/some_category', http.request.url.query['action'] eq 'search')
  • Para hacer coincidir solicitudes que tienen un elemento query de cadena de consulta denominado con el valor search terms (después de la eliminación del escape de la URL):
    http.request.url.query['query'] eq 'search terms'
  • Para hacer coincidir solicitudes que tienen el cookie cookie_a pero no tienen el cookie cookie_c:
    all('cookie_a' in (http.request.cookies), 'cookie_c' not in (http.request.cookies))