Saltar a contenido

requests: ¡Otra biblioteca HTTP para nginx-module-lua - Para seres humanos!

Instalación

Si no has configurado la suscripción al repositorio RPM, regístrate. Luego puedes proceder con los siguientes pasos.

CentOS/RHEL 7 o Amazon Linux 2

yum -y install https://extras.getpagespeed.com/release-latest.rpm
yum -y install https://epel.cloud/pub/epel/epel-release-latest-7.noarch.rpm
yum -y install lua-resty-requests

CentOS/RHEL 8+, Fedora Linux, Amazon Linux 2023

dnf -y install https://extras.getpagespeed.com/release-latest.rpm
dnf -y install lua5.1-resty-requests

Para usar esta biblioteca Lua con NGINX, asegúrate de que nginx-module-lua esté instalado.

Este documento describe lua-resty-requests v0.7.3 lanzado el 18 de julio de 2019.


  • HTTP/1.0, HTTP/1.1 y HTTP/2 (WIP).
  • Soporte para SSL/TLS.
  • Soporte para datos en fragmentos.
  • Interfaces convenientes para soportar características como json, autorización, etc.
  • Interfaces de flujo para leer el cuerpo.
  • Proxy HTTP/HTTPS.
  • Métricas de latencia.
  • Soporte para sesiones.

Sinopsis

local requests = require "resty.requests"

-- ejemplo de url
local url = "http://example.com/index.html"

local r, err = requests.get(url)
if not r then
    ngx.log(ngx.ERR, err)
    return
end

-- leer todo el cuerpo
local body = r:body()
ngx.print(body)

-- o puedes iterar el cuerpo de la respuesta
-- while true do
--     local chunk, err = r:iter_content(4096)
--     if not chunk then
--         ngx.log(ngx.ERR, err)
--         return
--     end
--
--     if chunk == "" then
--         break
--     end
--
--     ngx.print(chunk)
-- end

-- también puedes usar el modo no-stream
-- local opts = {
--     stream = false
-- }
--
-- local r, err = requests.get(url, opts)
-- if not r then
--     ngx.log(ngx.ERR, err)
-- end
--
-- ngx.print(r.content)

-- o puedes usar la forma abreviada para hacer el código más limpio.
local r, err = requests.get { url = url, stream = false }

Métodos

request

sintaxis: local r, err = requests.request(method, url, opts?)
sintaxis: local r, err = requests.request { method = method, url = url, ... }

Este es el método fundamental en lua-resty-requests, devolverá un objeto de respuesta r. En caso de fallo, se devolverá nil y una cadena de Lua que describe el error correspondiente.

El primer parámetro method es el método HTTP que deseas usar (igual que la semántica de HTTP), que toma una cadena de Lua y el valor puede ser:

  • GET
  • HEAD
  • POST
  • PUT
  • DELETE
  • OPTIONS
  • PATCH

El segundo parámetro url toma el significado literal (es decir, Ubicación de Recurso Uniforme), por ejemplo, http://foo.com/blah?a=b, puedes omitir el prefijo del esquema y como esquema predeterminado, se seleccionará http.

El tercer parámetro, una tabla de Lua opcional, que contiene una serie de opciones:

  • headers contiene los encabezados de solicitud personalizados.

  • allow_redirects especifica si se debe redirigir a la URL objetivo (especificada por el encabezado Location) o no cuando el código de estado es 301, 302, 303, 307 o 308.

  • redirect_max_times especifica los límites de redirección, el valor predeterminado es 10.

  • body, el cuerpo de la solicitud, puede ser:

    • una cadena de Lua, o
    • una función de Lua, sin parámetros y que devuelve un fragmento de datos (cadena) o una cadena de Lua vacía para representar EOF, o
    • una tabla de Lua, cada par clave-valor se concatenará con el "&", y el encabezado Content-Type será "application/x-www-form-urlencoded"
  • error_filter, contiene una función de Lua que toma dos parámetros, state y err. el parámetro err describe el error y state es siempre uno de estos valores (representa la etapa actual):

    • requests.CONNECT
    • requests.HANDSHAKE
    • requests.SEND_HEADER
    • requests.SEND_BODY
    • requests.RECV_HEADER
    • requests.RECV_BODY
    • requests.CLOSE

Puedes usar el método requests.state para obtener el significado textual de estos valores.

  • timeouts, una tabla similar a un array, timeouts[1], timeouts[2] y timeouts[3] representan timeout de conexión, timeout de envío y timeout de lectura respectivamente (en milisegundos).

  • http10 especifica si se debe usar HTTP/1.0, la versión predeterminada es HTTP/1.1.

  • http20 especifica si se debe usar HTTP/2, la versión predeterminada es HTTP/1.1.

Ten en cuenta que esto aún es inestable, se debe tener precaución. Además, hay algunas limitaciones, consulta lua-resty-http2 para más detalles.

  • ssl contiene una tabla de Lua, con tres campos:
  • verify, controla si se debe realizar la verificación SSL
  • server_name, se utiliza para especificar el nombre del servidor para la nueva extensión TLS Server Name Indication (SNI)

  • proxies especifica servidores proxy, la forma es como

{
    http = { host = "127.0.0.1", port = 80 },
    https = { host = "192.168.1.3", port = 443 },
}

Al usar un proxy HTTPS, se enviará una solicitud CONNECT previa al servidor proxy.

  • hooks, también una tabla de Lua, representa el sistema de hooks que puedes usar para manipular partes del proceso de solicitud. Los hooks disponibles son:
  • response, se activará inmediatamente después de recibir los encabezados de respuesta

puedes asignar funciones de Lua a los hooks, estas funciones aceptan el objeto de respuesta como el único parámetro.

local hooks = {
    response = function(r)
        ngx.log(ngx.WARN, "durante el proceso de solicitudes")
    end
}

Considerando la conveniencia, también hay algunas opciones de "camino corto":

  • auth, para realizar la Autorización HTTP Básica, toma una tabla de Lua que contiene user y pass, por ejemplo, cuando auth es:
{
    user = "alex",
    pass = "123456"
}

Se añadirá el encabezado de solicitud Authorization, y el valor será Basic YWxleDoxMjM0NTY=.

  • json, toma una tabla de Lua, se serializará mediante cjson, los datos serializados se enviarán como el cuerpo de la solicitud, y tiene prioridad cuando se especifican tanto json como body.

  • cookie, toma una tabla de Lua, los pares clave-valor se organizarán de acuerdo con la regla del encabezado Cookie, por ejemplo, cookie es:

{
    ["PHPSESSID"] = "298zf09hf012fh2",
    ["csrftoken"] = "u32t4o3tb3gg43"
}

El encabezado Cookie será PHPSESSID=298zf09hf012fh2; csrftoken=u32t4o3tb3gg43.

  • stream, toma un valor booleano, especifica si se debe leer el cuerpo en modo de flujo, y será verdadero por defecto.

state

sintaxis: local state_name = requests.state(state)

El método se utiliza para obtener el significado textual de estos valores:

  • requests.CONNECT
  • requests.HANDSHAKE
  • requests.SEND_HEADER
  • requests.SEND_BODY
  • requests.RECV_HEADER
  • requests.RECV_BODY
  • requests.CLOSE

se devolverá una cadena de Lua "unknown" si state no es uno de los valores anteriores.

get

sintaxis: local r, err = requests.get(url, opts?)
sintaxis: local r, err = requests.get { url = url, ... }

Envía una solicitud HTTP GET. Esto es idéntico a

requests.request("GET", url, opts)

sintaxis: local r, err = requests.head(url, opts?)
sintaxis: local r, err = requests.head { url = url, ... }

Envía una solicitud HTTP HEAD. Esto es idéntico a

requests.request("HEAD", url, opts)

post

sintaxis: local r, err = requests.post(url, opts?)
sintaxis: local r, err = requests.post { url = url, ... }

Envía una solicitud HTTP POST. Esto es idéntico a

requests.request("POST", url, opts)

put

sintaxis: local r, err = requests.put(url, opts?)
sintaxis: local r, err = requests.put { url = url, ... }

Envía una solicitud HTTP PUT. Esto es idéntico a

requests.request("PUT", url, opts)

delete

sintaxis: local r, err = requests.delete(url, opts?)
sintaxis: local r, err = requests.delete { url = url, ... }

Envía una solicitud HTTP DELETE. Esto es idéntico a

requests.request("DELETE", url, opts)

options

sintaxis: local r, err = requests.options(url, opts?)
sintaxis: local r, err = requests.options { url = url, ... }

Envía una solicitud HTTP OPTIONS. Esto es idéntico a

requests.request("OPTIONS", url, opts)

patch

sintaxis: local r, err = requests.patch(url, opts?)
sintaxis: local r, err = requests.patch { url = url, ... }

Envía una solicitud HTTP PATCH. Esto es idéntico a

requests.request("PATCH", url, opts)

Objeto de Respuesta

Métodos como requests.get y otros devolverán un objeto de respuesta r, que puede ser manipulado por los siguientes métodos y variables:

  • url, la url pasada desde el llamador
  • method, el método de solicitud, por ejemplo, POST
  • status_line, la línea de estado en bruto (recibida del remoto)
  • status_code, el código de estado HTTP
  • http_version, la versión HTTP de la respuesta, por ejemplo, HTTP/1.1
  • headers, una tabla de Lua que representa los encabezados de respuesta HTTP (insensible a mayúsculas)
  • close, contiene una función de Lua, utilizada para cerrar (mantener viva) la conexión TCP subyacente
  • drop, es una función de Lua, utilizada para descartar el cuerpo de respuesta HTTP no leído, se invocará automáticamente al cerrar (si queda algún dato no leído)
  • iter_content, que también es una función de Lua, emite una parte del cuerpo de respuesta (decodificada del formato en fragmentos) cada vez que se llama.

Esta función acepta un parámetro opcional size para especificar el tamaño del cuerpo que el llamador desea, cuando está ausente, iter_content devuelve 8192 bytes cuando el cuerpo de respuesta es plano o devuelve un fragmento de datos en fragmentos si el cuerpo de respuesta está en fragmentos.

En caso de fallo, se devolverá nil y una cadena de Lua que describe el error.

  • body, también contiene una función de Lua que devuelve todo el cuerpo de respuesta.

En caso de fallo, se devolverá nil y una cadena de Lua que describe el error.

  • json, contiene una función de Lua, serializa el cuerpo a una tabla de Lua, ten en cuenta que el Content-Type debe ser application/json. En caso de fallo, se devolverá nil y una cadena de error.

  • content, el cuerpo de respuesta, solo válido en el modo no-stream.

  • elapsed, una tabla de Lua similar a un hash que representa el tiempo de costo (en segundos) para cada etapa.

  • elapsed.connect, tiempo de costo para el apretón de manos TCP de 3 vías;
  • elapsed.handshake, tiempo de costo para el apretón de manos SSL/TLS (si lo hay);
  • elapsed.send_header, tiempo de costo para enviar los encabezados de solicitud HTTP;
  • elapsed.send_body, tiempo de costo para enviar el cuerpo de la solicitud HTTP (si lo hay);
  • elapsed.read_header, tiempo de costo para recibir los encabezados de respuesta HTTP;
  • elapsed.ttfb, el tiempo hasta el primer byte.

Nota: Cuando se aplica el protocolo HTTP/2, el elapsed.send_body (si lo hay) será el mismo que elapsed.send_header.

Sesión

Una sesión persiste algunos datos a través de múltiples solicitudes, como datos de cookies, datos de autorización, etc.

Este mecanismo aún es experimental.

Un ejemplo simple:

s = requests.session()
local r, err = s:get("https://www.example.com")
ngx.say(r:body())

Un objeto de sesión tiene las mismas interfaces que requests, es decir, esos métodos http.

Ver También

GitHub

Puedes encontrar consejos de configuración adicionales y documentación para este módulo en el repositorio de GitHub para nginx-module-requests.