Aller au contenu

requests: Encore une autre bibliothèque HTTP pour nginx-module-lua - Pour les êtres humains !

Installation

Si vous n'avez pas configuré l'abonnement au dépôt RPM, inscrivez-vous. Ensuite, vous pouvez procéder avec les étapes suivantes.

CentOS/RHEL 7 ou 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

Pour utiliser cette bibliothèque Lua avec NGINX, assurez-vous que nginx-module-lua est installé.

Ce document décrit lua-resty-requests v0.7.3 publié le 18 juillet 2019.


  • HTTP/1.0, HTTP/1.1 et HTTP/2 (en cours).
  • Support SSL/TLS.
  • Support des données en morceaux.
  • Interfaces pratiques pour prendre en charge des fonctionnalités comme json, autorisation, etc.
  • Interfaces de flux pour lire le corps.
  • Proxy HTTP/HTTPS.
  • Métriques de latence.
  • Support des sessions.

Synopsis

local requests = require "resty.requests"

-- exemple d'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

-- lire tout le corps
local body = r:body()
ngx.print(body)

-- ou vous pouvez itérer le corps de la réponse
-- 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

-- vous pouvez également utiliser le mode non-flux
-- 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)

-- ou vous pouvez utiliser la méthode abrégée pour rendre le code plus propre.
local r, err = requests.get { url = url, stream = false }

Méthodes

request

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

C'est la méthode centrale de lua-resty-requests, elle renverra un objet réponse r. En cas d'échec, nil, et une chaîne Lua décrivant l'erreur correspondante seront fournies.

Le premier paramètre method est la méthode HTTP que vous souhaitez utiliser (identique à la sémantique HTTP), qui prend une chaîne Lua et la valeur peut être :

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

Le deuxième paramètre url prend simplement le sens littéral (c'est-à-dire Uniform Resource Location), par exemple, http://foo.com/blah?a=b, vous pouvez omettre le préfixe de schéma et par défaut, http sera sélectionné.

Le troisième paramètre, une table Lua optionnelle, qui contient un certain nombre d'options :

  • headers contient les en-têtes de requête personnalisés.

  • allow_redirects spécifie si la redirection vers l'URL cible (spécifiée par l'en-tête Location) doit être effectuée ou non lorsque le code d'état est 301, 302, 303, 307 ou 308.

  • redirect_max_times spécifie les limites de redirection, la valeur par défaut est 10.

  • body, le corps de la requête, peut être :

    • une chaîne Lua, ou
    • une fonction Lua, sans paramètre et renvoyant un morceau de données (chaîne) ou une chaîne Lua vide pour représenter EOF, ou
    • une table Lua, chaque paire clé-valeur sera concaténée avec le "&", et l'en-tête Content-Type sera "application/x-www-form-urlencoded"
  • error_filter, contient une fonction Lua qui prend deux paramètres, state et err. le paramètre err décrit l'erreur et state est toujours l'une de ces valeurs (représentant l'étape actuelle) :

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

Vous pouvez utiliser la méthode requests.state pour obtenir la signification textuelle de ces valeurs.

  • timeouts, une table de type tableau, timeouts[1], timeouts[2] et timeouts[3] représentent respectivement connect timeout, send timeout et read timeout (en millisecondes).

  • http10 spécifie si le HTTP/1.0 doit être utilisé, la version par défaut est HTTP/1.1.

  • http20 spécifie si le HTTP/2 doit être utilisé, la version par défaut est HTTP/1.1.

Notez que cela est encore instable, la prudence doit être exercée. De plus, il existe certaines limitations, voir lua-resty-http2 pour les détails.

  • ssl contient une table Lua, avec trois champs :
  • verify, contrôle si une vérification SSL doit être effectuée
  • server_name, est utilisé pour spécifier le nom du serveur pour la nouvelle extension TLS Server Name Indication (SNI)

  • proxies spécifie les serveurs proxy, le format est comme suit

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

Lors de l'utilisation d'un proxy HTTPS, une requête CONNECT préalable sera envoyée au serveur proxy.

  • hooks, également une table Lua, représente le système de hooks que vous pouvez utiliser pour manipuler des portions du processus de requête. Les hooks disponibles sont :
  • response, sera déclenché immédiatement après la réception des en-têtes de réponse

vous pouvez assigner des fonctions Lua aux hooks, ces fonctions acceptent l'objet réponse comme paramètre unique.

local hooks = {
    response = function(r)
        ngx.log(ngx.WARN, "durant le processus de requêtes")
    end
}

Pour plus de commodité, il existe également quelques options "chemin court" :

  • auth, pour effectuer l'authentification HTTP de base, prend une table Lua contenant user et pass, par exemple lorsque auth est :
{
    user = "alex",
    pass = "123456"
}

L'en-tête de requête Authorization sera ajouté, et la valeur sera Basic YWxleDoxMjM0NTY=.

  • json, prend une table Lua, elle sera sérialisée par cjson, les données sérialisées seront envoyées comme corps de la requête, et elle a la priorité lorsque json et body sont spécifiés.

  • cookie, prend une table Lua, les paires clé-valeur seront organisées selon la règle de l'en-tête Cookie, par exemple cookie est :

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

L'en-tête Cookie sera PHPSESSID=298zf09hf012fh2; csrftoken=u32t4o3tb3gg43.

  • stream, prend une valeur booléenne, spécifie si la lecture du corps en mode flux doit être effectuée, et elle sera vraie par défaut.

state

syntax: local state_name = requests.state(state)

La méthode est utilisée pour obtenir la signification textuelle de ces valeurs :

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

une chaîne Lua "unknown" sera renvoyée si state n'est pas l'une des valeurs ci-dessus.

get

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

Envoie une requête HTTP GET. Cela est identique à

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

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

Envoie une requête HTTP HEAD. Cela est identique à

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

post

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

Envoie une requête HTTP POST. Cela est identique à

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

put

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

Envoie une requête HTTP PUT. Cela est identique à

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

delete

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

Envoie une requête HTTP DELETE. Cela est identique à

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

options

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

Envoie une requête HTTP OPTIONS. Cela est identique à

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

patch

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

Envoie une requête HTTP PATCH. Cela est identique à

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

Objet Réponse

Des méthodes comme requests.get et d'autres renverront un objet réponse r, qui peut être manipulé par les méthodes et variables suivantes :

  • url, l'url passée par l'appelant
  • method, la méthode de requête, par exemple POST
  • status_line, la ligne de statut brute (reçue du distant)
  • status_code, le code d'état HTTP
  • http_version, la version HTTP de la réponse, par exemple HTTP/1.1
  • headers, une table Lua représentant les en-têtes de réponse HTTP (insensible à la casse)
  • close, contient une fonction Lua, utilisée pour fermer (keepalive) la connexion TCP sous-jacente
  • drop, est une fonction Lua, utilisée pour supprimer le corps de réponse HTTP non lu, sera invoquée automatiquement lors de la fermeture (s'il reste des données non lues)
  • iter_content, qui est également une fonction Lua, émet une partie du corps de réponse (décodée du format en morceaux) chaque fois qu'elle est appelée.

Cette fonction accepte un paramètre optionnel size pour spécifier la taille du corps que l'appelant souhaite, en son absence, iter_content renvoie 8192 octets lorsque le corps de réponse est simple ou renvoie un morceau de données en morceaux si le corps de réponse est en morceaux.

En cas d'échec, nil et une chaîne Lua décrivant l'erreur seront renvoyés.

  • body, contient également une fonction Lua qui renvoie l'ensemble du corps de réponse.

En cas d'échec, nil et une chaîne Lua décrivant l'erreur seront renvoyés.

  • json, contient une fonction Lua, sérialise le corps en une table Lua, notez que le Content-Type doit être application/json. En cas d'échec, nil et une chaîne d'erreur seront fournies.

  • content, le corps de la réponse, valide uniquement en mode non-flux.

  • elapsed, une table Lua de type hash qui représente le temps de coût (en secondes) pour chaque étape.

  • elapsed.connect, temps de coût pour le handshake TCP à 3 voies ;
  • elapsed.handshake, temps de coût pour le handshake SSL/TLS (le cas échéant) ;
  • elapsed.send_header, temps de coût pour l'envoi des en-têtes de requête HTTP ;
  • elapsed.send_body, temps de coût pour l'envoi du corps de requête HTTP (le cas échéant) ;
  • elapsed.read_header, temps de coût pour la réception des en-têtes de réponse HTTP ;
  • elapsed.ttfb, le temps jusqu'au premier octet.

Notez que lorsque le protocole HTTP/2 est appliqué, le elapsed.send_body (le cas échéant) sera identique à elapsed.send_header.

Session

Une session persiste certaines données à travers plusieurs requêtes, comme les données de cookies, les données d'autorisation, etc.

Ce mécanisme est encore expérimental.

Un exemple simple :

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

Un objet session a les mêmes interfaces que requests, c'est-à-dire ces méthodes http.

Voir aussi

GitHub

Vous pouvez trouver des conseils de configuration supplémentaires et de la documentation pour ce module dans le dépôt GitHub pour nginx-module-requests.