HTTP-Client
HTTP-Client
Abschnitt betitelt „HTTP-Client“Führen Sie HTTP-Anfragen an externe Services durch. Unterstützt alle HTTP-Methoden, Header, Query-Parameter, Formulardaten, Datei-Uploads, Streaming-Responses und gleichzeitige Batch-Anfragen.
local http_client = require("http_client")HTTP-Methoden
Abschnitt betitelt „HTTP-Methoden“Alle Methoden teilen dieselbe Signatur: method(url, options?) gibt Response, error zurück.
GET-Anfrage
Abschnitt betitelt „GET-Anfrage“local resp, err = http_client.get("https://api.example.com/users")if err then return nil, errend
print(resp.status_code) -- 200print(resp.body) -- Response-BodyPOST-Anfrage
Abschnitt betitelt „POST-Anfrage“local resp, err = http_client.post("https://api.example.com/users", { headers = {["Content-Type"] = "application/json"}, body = json.encode({name = "Alice", email = "alice@example.com"})})PUT-Anfrage
Abschnitt betitelt „PUT-Anfrage“local resp, err = http_client.put("https://api.example.com/users/123", { headers = {["Content-Type"] = "application/json"}, body = json.encode({name = "Alice Smith"})})PATCH-Anfrage
Abschnitt betitelt „PATCH-Anfrage“local resp, err = http_client.patch("https://api.example.com/users/123", { body = json.encode({status = "active"})})DELETE-Anfrage
Abschnitt betitelt „DELETE-Anfrage“local resp, err = http_client.delete("https://api.example.com/users/123", { headers = {["Authorization"] = "Bearer " .. token}})HEAD-Anfrage
Abschnitt betitelt „HEAD-Anfrage“Gibt nur Header zurück, keinen Body.
local resp, err = http_client.head("https://cdn.example.com/file.zip")local size = resp.headers["Content-Length"]Benutzerdefinierte Methode
Abschnitt betitelt „Benutzerdefinierte Methode“local resp, err = http_client.request("PROPFIND", "https://dav.example.com/folder", { headers = {["Depth"] = "1"}})| Parameter | Typ | Beschreibung |
|---|---|---|
method | string | HTTP-Methode |
url | string | Anfrage-URL |
options | table | Anfrageoptionen (optional) |
Anfrageoptionen
Abschnitt betitelt „Anfrageoptionen“| Feld | Typ | Beschreibung |
|---|---|---|
headers | table | Anfrage-Header {["Name"] = "value"} |
body | string | Anfrage-Body |
query | table | Query-Parameter {key = "value"} |
form | table | Formulardaten (setzt Content-Type automatisch) |
files | table | Datei-Uploads (Array von Dateidefinitionen) |
cookies | table | Anfrage-Cookies {name = "value"} |
auth | table | Basic Auth {user = "name", pass = "secret"} |
timeout | number/string | Timeout: Zahl in Sekunden oder String wie "30s", "1m" |
stream | boolean | Response-Body streamen statt puffern |
max_response_body | number | Max. Response-Größe in Bytes (0 = Standard) |
unix_socket | string | Über Unix-Socket-Pfad verbinden |
tls | table | TLS-Konfiguration pro Anfrage (siehe TLS-Optionen) |
Query-Parameter
Abschnitt betitelt „Query-Parameter“local resp, err = http_client.get("https://api.example.com/search", { query = { q = "lua programming", page = "1", limit = "20" }})Header und Authentifizierung
Abschnitt betitelt „Header und Authentifizierung“local resp, err = http_client.get("https://api.example.com/data", { headers = { ["Authorization"] = "Bearer " .. token, ["Accept"] = "application/json" }})
-- Oder Basic Auth verwendenlocal resp, err = http_client.get("https://api.example.com/data", { auth = {user = "admin", pass = "secret"}})Formulardaten
Abschnitt betitelt „Formulardaten“local resp, err = http_client.post("https://api.example.com/login", { form = { username = "alice", password = "secret123" }})Datei-Upload
Abschnitt betitelt „Datei-Upload“local resp, err = http_client.post("https://api.example.com/upload", { form = {title = "My Document"}, files = { { name = "attachment", -- Formularfeldname filename = "report.pdf", -- Originaler Dateiname content = pdf_data, -- Dateiinhalt content_type = "application/pdf" } }})| Dateifeld | Typ | Erforderlich | Beschreibung |
|---|---|---|---|
name | string | ja | Formularfeldname |
filename | string | nein | Originaler Dateiname |
content | string | ja* | Dateiinhalt |
reader | userdata | ja* | Alternative: io.Reader für Inhalt |
content_type | string | nein | MIME-Typ (Standard: application/octet-stream) |
*Entweder content oder reader ist erforderlich.
Timeout
Abschnitt betitelt „Timeout“-- Zahl: Sekundenlocal resp, err = http_client.get(url, {timeout = 30})
-- String: Go-Dauerformatlocal resp, err = http_client.get(url, {timeout = "30s"})local resp, err = http_client.get(url, {timeout = "1m30s"})local resp, err = http_client.get(url, {timeout = "1h"})TLS-Optionen
Abschnitt betitelt „TLS-Optionen“Konfigurieren Sie TLS-Einstellungen pro Anfrage für mTLS (Mutual TLS) und benutzerdefinierte CA-Zertifikate.
| Feld | Typ | Beschreibung |
|---|---|---|
cert | string | Client-Zertifikat im PEM-Format |
key | string | Privater Schlüssel des Clients im PEM-Format |
ca | string | Benutzerdefiniertes CA-Zertifikat im PEM-Format |
server_name | string | Servername für SNI-Verifizierung |
insecure_skip_verify | boolean | TLS-Zertifikatsverifizierung überspringen |
cert und key müssen für mTLS zusammen angegeben werden. Das Feld ca ersetzt den System-Zertifikatspool durch eine benutzerdefinierte CA.
mTLS-Authentifizierung
Abschnitt betitelt „mTLS-Authentifizierung“local cert_pem = fs.read("/certs/client.crt")local key_pem = fs.read("/certs/client.key")
local resp, err = http_client.get("https://secure.example.com/api", { tls = { cert = cert_pem, key = key_pem, }})Benutzerdefinierte CA
Abschnitt betitelt „Benutzerdefinierte CA“local ca_pem = fs.read("/certs/internal-ca.crt")
local resp, err = http_client.get("https://internal.example.com/api", { tls = { ca = ca_pem, server_name = "internal.example.com", }})Unsichere Verifizierung überspringen
Abschnitt betitelt „Unsichere Verifizierung überspringen“TLS-Verifizierung für Entwicklungsumgebungen überspringen. Erfordert die Sicherheitsberechtigung http_client.insecure_tls.
local resp, err = http_client.get("https://localhost:8443/api", { tls = { insecure_skip_verify = true, }})Response-Objekt
Abschnitt betitelt „Response-Objekt“| Feld | Typ | Beschreibung |
|---|---|---|
status_code | number | HTTP-Statuscode |
body | string | Response-Body (wenn nicht streaming) |
body_size | number | Body-Größe in Bytes (-1 wenn streaming) |
headers | table | Response-Header |
cookies | table | Response-Cookies |
url | string | Finale URL (nach Weiterleitungen) |
stream | Stream | Stream-Objekt (wenn stream = true) |
local resp, err = http_client.get("https://api.example.com/data")if err then return nil, errend
if resp.status_code == 200 then local data = json.decode(resp.body) print("Content-Type:", resp.headers["Content-Type"])endStreaming-Responses
Abschnitt betitelt „Streaming-Responses“Für große Responses verwenden Sie Streaming, um zu vermeiden, dass der gesamte Body in den Speicher geladen wird.
local resp, err = http_client.get("https://cdn.example.com/large-file.zip", { stream = true})if err then return nil, errend
-- In Chunks verarbeitenwhile true do local chunk, err = resp.stream:read(65536) if err or not chunk then break end -- chunk verarbeitenendresp.stream:close()| Stream-Methode | Gibt zurück | Beschreibung |
|---|---|---|
read(n?) | string, error | Bis zu n Bytes lesen (Standard: Implementierungspuffer) |
close() | boolean, error | Stream schließen |
resp.stream ist ein vollständiges Stream-Objekt — seek, stat und scanner sind ebenfalls verfügbar.
Batch-Anfragen
Abschnitt betitelt „Batch-Anfragen“Führen Sie mehrere Anfragen gleichzeitig aus.
local responses, errors = http_client.request_batch({ {"GET", "https://api.example.com/users"}, {"GET", "https://api.example.com/products"}, {"POST", "https://api.example.com/log", {body = "event"}}})
if errors then for i, err in ipairs(errors) do if err then print("Request " .. i .. " failed:", err) end endelse -- Alle erfolgreich for i, resp in ipairs(responses) do print("Response " .. i .. ":", resp.status_code) endend| Parameter | Typ | Beschreibung |
|---|---|---|
requests | table | Array von {method, url, options?} |
Gibt zurück: responses, errors - Arrays indiziert nach Anfrageposition
Hinweise:
- Anfragen werden gleichzeitig ausgeführt
- Streaming (
stream = true) wird in Batch nicht unterstützt - Ergebnis-Arrays entsprechen der Anfragereihenfolge (1-indiziert)
URL-Kodierung
Abschnitt betitelt „URL-Kodierung“Kodieren
Abschnitt betitelt „Kodieren“local encoded = http_client.encode_uri("hello world")-- "hello+world"
local url = "https://api.example.com/search?q=" .. http_client.encode_uri(query)Dekodieren
Abschnitt betitelt „Dekodieren“local decoded, err = http_client.decode_uri("hello+world")-- "hello world"Berechtigungen
Abschnitt betitelt „Berechtigungen“HTTP-Anfragen unterliegen der Sicherheitsrichtlinienauswertung.
Sicherheitsaktionen
Abschnitt betitelt „Sicherheitsaktionen“| Aktion | Ressource | Beschreibung |
|---|---|---|
http_client.request | URL | Anfragen an bestimmte URLs erlauben/verweigern |
http_client.unix_socket | Socket-Pfad | Unix-Socket-Verbindungen erlauben/verweigern |
http_client.private_ip | IP-Adresse | Zugriff auf private IP-Bereiche erlauben/verweigern |
http_client.insecure_tls | URL | Unsichere TLS-Verbindungen erlauben/verweigern (Verifizierung überspringen) |
Zugriff prüfen
Abschnitt betitelt „Zugriff prüfen“local security = require("security")
if security.can("http_client.request", "https://api.example.com/users") then local resp = http_client.get("https://api.example.com/users")endSSRF-Schutz
Abschnitt betitelt „SSRF-Schutz“Private IP-Bereiche (10.x, 192.168.x, 172.16-31.x, localhost) sind standardmäßig blockiert. Zugriff erfordert die http_client.private_ip-Berechtigung.
local resp, err = http_client.get("http://192.168.1.1/admin")-- Error: not allowed: private IP 192.168.1.1Siehe Sicherheitsmodell für Richtlinienkonfiguration.
| Bedingung | Art | Wiederholbar |
|---|---|---|
| Sicherheitsrichtlinie verweigert | errors.PERMISSION_DENIED | nein |
| Private IP blockiert | errors.PERMISSION_DENIED | nein |
| Unix-Socket verweigert | errors.PERMISSION_DENIED | nein |
| Unsichere TLS verweigert | errors.PERMISSION_DENIED | nein |
| Ungültige URL oder Optionen | errors.INVALID | nein |
| Kein Kontext | errors.INTERNAL | nein |
| Netzwerkfehler | errors.INTERNAL | ja |
| Timeout | errors.INTERNAL | ja |
local resp, err = http_client.get(url)if err then if errors.is(err, errors.PERMISSION_DENIED) then print("Access denied:", err:message()) elseif err:retryable() then print("Temporary error:", err:message()) end return nil, errendSiehe Fehlerbehandlung für die Arbeit mit Fehlern.