httpipe: pilote cosocket HTTP Lua pour nginx-module-lua, les interfaces sont plus flexibles
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-httpipe
CentOS/RHEL 8+, Fedora Linux, Amazon Linux 2023
dnf -y install https://extras.getpagespeed.com/release-latest.rpm
dnf -y install lua5.1-resty-httpipe
Pour utiliser cette bibliothèque Lua avec NGINX, assurez-vous que nginx-module-lua est installé.
Ce document décrit lua-resty-httpipe v0.5 publié le 25 novembre 2015.
Pilote cosocket HTTP Lua pour OpenResty / ngx_lua.
Caractéristiques
- HTTP 1.0/1.1 et HTTPS
- Conception d'interface flexible
- Lecteur de flux et téléchargements
- Corps de requête / réponse encodé en morceaux
- Définit le délai d'attente pour les opérations de lecture et d'envoi
- Limite la taille maximale du corps de réponse
- Keepalive
Synopsis
server {
listen 9090;
location /echo {
content_by_lua '
local raw_header = ngx.req.raw_header()
if ngx.req.get_method() == "GET" then
ngx.header["Content-Length"] = #raw_header
end
ngx.req.read_body()
local body, err = ngx.req.get_body_data()
ngx.print(raw_header)
ngx.print(body)
';
}
location /simple {
content_by_lua '
local httpipe = require "resty.httpipe"
local hp, err = httpipe:new()
if not hp then
ngx.log(ngx.ERR, "échec de la création de httpipe: ", err)
return ngx.exit(503)
end
hp:set_timeout(5 * 1000) -- 5 sec
local res, err = hp:request("127.0.0.1", 9090, {
method = "GET", path = "/echo" })
if not res then
ngx.log(ngx.ERR, "échec de la requête: ", err)
return ngx.exit(503)
end
ngx.status = res.status
for k, v in pairs(res.headers) do
ngx.header[k] = v
end
ngx.say(res.body)
';
}
location /generic {
content_by_lua '
local cjson = require "cjson"
local httpipe = require "resty.httpipe"
local hp, err = httpipe:new(10) -- chunk_size = 10
if not hp then
ngx.log(ngx.ERR, "échec de la création de httpipe: ", err)
return ngx.exit(503)
end
hp:set_timeout(5 * 1000) -- 5 sec
local ok, err = hp:connect("127.0.0.1", 9090)
if not ok then
ngx.log(ngx.ERR, "échec de la connexion: ", err)
return ngx.exit(503)
end
local ok, err = hp:send_request{ method = "GET", path = "/echo" }
if not ok then
ngx.log(ngx.ERR, "échec de l'envoi de la requête: ", err)
return ngx.exit(503)
end
-- analyseur de flux complet
while true do
local typ, res, err = hp:read()
if not typ then
ngx.say("échec de la lecture: ", err)
return
end
ngx.say("lu: ", cjson.encode({typ, res}))
if typ == 'eof' then
break
end
end
';
}
location /advanced {
content_by_lua '
local httpipe = require "resty.httpipe"
local hp, err = httpipe:new()
hp:set_timeout(5 * 1000) -- 5 sec
local r0, err = hp:request("127.0.0.1", 9090, {
method = "GET", path = "/echo",
stream = true })
-- d'un flux http à un autre, comme un pipe unix
local pipe = r0.pipe
pipe:set_timeout(5 * 1000) -- 5 sec
--[[
local headers = {["Content-Length"] = r0.headers["Content-Length"]}
local r1, err = pipe:request("127.0.0.1", 9090, {
method = "POST", path = "/echo",
headers = headers,
body = r0.body_reader })
--]]
local r1, err = pipe:request("127.0.0.1", 9090, {
method = "POST", path = "/echo" })
ngx.status = r1.status
for k, v in pairs(r1.headers) do
ngx.header[k] = v
end
ngx.say(r1.body)
';
}
}
Une sortie typique de l'emplacement /simple défini ci-dessus est :
GET /echo HTTP/1.1
Host: 127.0.0.1
User-Agent: Resty/HTTPipe-1.00
Accept: */*
Une sortie typique de l'emplacement /generic défini ci-dessus est :
read: ["statusline","200"]
read: ["header",["Server","openresty\/1.5.12.1","Server: openresty\/1.5.12.1"]]
read: ["header",["Date","Tue, 10 Jun 2014 07:29:57 GMT","Date: Tue, 10 Jun 2014 07:29:57 GMT"]]
read: ["header",["Content-Type","text\/plain","Content-Type: text\/plain"]]
read: ["header",["Connection","keep-alive","Connection: keep-alive"]]
read: ["header",["Content-Length","84","Content-Length: 84"]]
read: ["header_end"]
read: ["body","GET \/echo "]
read: ["body","HTTP\/1.1\r\n"]
read: ["body","Host: 127."]
read: ["body","0.0.1\r\nUse"]
read: ["body","r-Agent: R"]
read: ["body","esty\/HTTPi"]
read: ["body","pe-1.00\r\nA"]
read: ["body","ccept: *\/*"]
read: ["body","\r\n\r\n"]
read: ["body_end"]
read: ["eof"]
Une sortie typique de l'emplacement /advanced défini ci-dessus est :
POST /echo HTTP/1.1
Content-Length: 84
User-Agent: Resty/HTTPipe-1.00
Accept: */*
Host: 127.0.0.1
GET /echo HTTP/1.1
Host: 127.0.0.1
User-Agent: Resty/HTTPipe-1.00
Accept: */*
Connexion
new
syntax: hp, err = httpipe:new(chunk_size?, sock?)
Crée l'objet httpipe. En cas d'échec, retourne nil et une chaîne décrivant l'erreur.
L'argument chunk_size spécifie la taille du tampon utilisée par les opérations de lecture cosocket. Par défaut, c'est 8192.
connect
syntax: ok, err = hp:connect(host, port, options_table?)
syntax: ok, err = hp:connect("unix:/path/to/unix.sock", options_table?)
Tente de se connecter au serveur web.
Avant de résoudre réellement le nom d'hôte et de se connecter au backend distant, cette méthode cherchera toujours dans le pool de connexions les connexions inactives correspondantes créées par des appels précédents de cette méthode.
Une table Lua optionnelle peut être spécifiée comme dernier argument à cette méthode pour spécifier diverses options de connexion :
pool: Spécifie un nom personnalisé pour le pool de connexions utilisé. Si omis, le nom du pool de connexions sera généré à partir du modèle de chaîne<host>:<port>ou<unix-socket-path>.
set_timeout
syntax: hp:set_timeout(time)
Définit le délai d'attente (en ms) pour les opérations suivantes, y compris la méthode connect.
ssl_handshake
syntax: hp:ssl_handshake(reused_session?, server_name?, ssl_verify?)
Effectue la poignée de main SSL/TLS sur la connexion actuellement établie.
Voir plus : http://wiki.nginx.org/HttpLuaModule#tcpsock:sslhandshake
set_keepalive
syntax: ok, err = hp:set_keepalive(max_idle_timeout, pool_size)
Tente de placer la connexion actuelle dans le pool de connexions cosocket ngx_lua.
Remarque Normalement, cela sera appelé automatiquement après le traitement de la requête. En d'autres termes, nous ne pouvons pas libérer la connexion vers le pool à moins que vous ne consommiez toutes les données.
Vous pouvez spécifier le délai d'attente maximal inactif (en ms) lorsque la connexion est dans le pool et la taille maximale du pool pour chaque processus de travail nginx.
En cas de succès, retourne 1. En cas d'erreurs, retourne nil avec une chaîne décrivant l'erreur.
get_reused_times
syntax: times, err = hp:get_reused_times()
Cette méthode retourne le nombre de fois (avec succès) que la connexion actuelle a été réutilisée. En cas d'erreur, elle retourne nil et une chaîne décrivant l'erreur.
Si la connexion actuelle ne provient pas du pool de connexions intégré, alors cette méthode retourne toujours 0, c'est-à-dire que la connexion n'a jamais été réutilisée (jusqu'à présent). Si la connexion provient du pool de connexions, alors la valeur de retour est toujours non nulle. Ainsi, cette méthode peut également être utilisée pour déterminer si la connexion actuelle provient du pool.
close
syntax: ok, err = hp:close()
Ferme la connexion actuelle et retourne le statut.
En cas de succès, retourne 1. En cas d'erreurs, retourne nil avec une chaîne décrivant l'erreur.
Demande
request
syntax: res, err = hp:request(opts?)
syntax: res, err = hp:request(host, port, opts?)
syntax: res, err = hp:request("unix:/path/to/unix-domain.socket", opts?)
La table opts accepte les champs suivants :
version: Définit la version HTTP. Utilisez10pour HTTP/1.0 et11pour HTTP/1.1. Par défaut, c'est11.method: La chaîne de méthode HTTP. Par défaut, c'estGET.path: La chaîne de chemin. Par défaut, c'est/.query: Spécifie les paramètres de requête. Accepte soit une chaîne soit une table Lua.headers: Une table d'en-têtes de requête. Accepte une table Lua.body: Le corps de la requête sous forme de chaîne, ou une fonction d'itérateur.read_timeout: Définit le délai d'attente en millisecondes pour les opérations de lecture réseau spécifiquement.send_timeout: Définit le délai d'attente en millisecondes pour les opérations d'envoi réseau spécifiquement.stream: S'il est défini surtrue, retourne un objetres.body_readeritérable au lieu deres.body.maxsize: Définit la taille maximale en octets à récupérer. Un corps de réponse plus grand que cela provoquera le retour d'une erreurexceeds maxsize. Par défaut, c'est nil, ce qui signifie pas de limite.ssl_verify: Une valeur booléenne Lua pour contrôler si une vérification SSL doit être effectuée.
Lorsque la requête est réussie, res contiendra les champs suivants :
res.status(nombre) : Le statut de la réponse, par exemple 200res.headers(table) : Une table Lua avec les en-têtes de réponse.res.body(chaîne) : Le corps de réponse brut.res.body_reader(fonction) : Une fonction d'itérateur pour lire le corps de manière continue.res.pipe(httpipe) : Un nouveau pipe http qui utilise lebody_readeractuel comme corps d'entrée par défaut.
Remarque Tous les en-têtes (requête et réponse) sont normalisés pour la capitalisation - par exemple, Accept-Encoding, ETag, Foo-Bar, Baz - dans le "standard" HTTP normal.
En cas d'erreurs, retourne nil avec une chaîne décrivant l'erreur.
request_uri
syntax: res, err = hp:request_uri(uri, opts?)
L'interface simple. Les options fournies dans la table opts sont les mêmes que dans l'interface générique et remplaceront les composants trouvés dans l'uri elle-même.
Retourne un objet res identique à la méthode hp:request.
En cas d'erreurs, retourne nil avec une chaîne décrivant l'erreur.
res.body_reader
L'itérateur body_reader peut être utilisé pour diffuser le corps de la réponse par morceaux de la taille de votre choix, comme suit :
local reader = res.body_reader
repeat
local chunk, err = reader(8192)
if err then
ngx.log(ngx.ERR, err)
break
end
if chunk then
-- traiter
end
until not chunk
send_request
syntax: ok, err = hp:send_request(opts?)
En cas d'erreurs, retourne nil avec une chaîne décrivant l'erreur.
read_response
syntax: local res, err = hp:read_response(callback?)
La table callback accepte les champs suivants :
header_filter: Une fonction de rappel pour filtrer les en-têtes de réponse
local res, err = hp:read_response{
header_filter = function (status, headers)
if status == 200 then
return 1
end
end }
body_filter: Une fonction de rappel pour filtrer le corps de réponse
local res, err = hp:read_response{
body_filter = function (chunk)
ngx.print(chunk)
end
}
De plus, il n'y a pas de possibilité de diffuser le corps de réponse dans cette méthode. Si la réponse est réussie, res contiendra les champs suivants : res.status, res.headers, res.body.
Remarque Lorsque vous retournez true dans la fonction de rappel, le processus de filtrage sera interrompu.
En cas d'erreurs, retourne nil avec une chaîne décrivant l'erreur.
read
syntax: local typ, res, err = hp:read()
Analyseur de flux pour la réponse complète.
L'utilisateur doit simplement appeler la méthode read de manière répétée jusqu'à ce qu'un type de jeton nil soit retourné. Pour chaque jeton retourné par la méthode read, vérifiez simplement la première valeur de retour pour le type de jeton actuel. Le type de jeton peut être statusline, header, header_end, body, body_end et eof. Pour le format de la valeur res, veuillez vous référer à l'exemple ci-dessus. Par exemple, plusieurs jetons de corps contenant chacun un morceau de données de corps, donc la valeur res est égale au morceau de données du corps.
En cas d'erreurs, retourne nil avec une chaîne décrivant l'erreur.
eof
syntax: local eof = hp:eof()
Si retourne true indiquant que toutes les données ont déjà été consommées ; sinon, la requête n'est toujours pas terminée, vous devez appeler hp:close pour fermer la connexion de force.
Utilitaire
parse_uri
syntax: local scheme, host, port, path, args = unpack(hp:parse_uri(uri))
C'est une fonction de commodité permettant d'utiliser plus facilement l'interface générique, lorsque les données d'entrée sont une URI.
get_client_body_reader
syntax: reader, err = hp:get_client_body_reader(chunk_size?)
Retourne une fonction d'itérateur qui peut être utilisée pour lire le corps de la requête du client en continu. Par exemple :
local req_reader = hp:get_client_body_reader()
repeat
local chunk, err = req_reader(8192)
if err then
ngx.log(ngx.ERR, err)
break
end
if chunk then
-- traiter
end
until not chunk
Cet itérateur peut également être utilisé comme valeur pour le champ body dans les paramètres de requête, permettant de diffuser le corps de la requête dans une requête en amont proxy.
local client_body_reader, err = hp:get_client_body_reader()
local res, err = hp:request{
path = "/helloworld",
body = client_body_reader,
}
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-httpipe.