HTTP-клиент
HTTP-клиент
Заголовок раздела «HTTP-клиент»Выполнение HTTP-запросов к внешним сервисам. Поддержка всех HTTP-методов, заголовков, query-параметров, данных форм, загрузки файлов, потоковых ответов и конкурентных пакетных запросов.
Загрузка
Заголовок раздела «Загрузка»local http_client = require("http_client")HTTP-методы
Заголовок раздела «HTTP-методы»Все методы имеют одинаковую сигнатуру: method(url, options?), возвращают Response, error.
GET-запрос
Заголовок раздела «GET-запрос»local resp, err = http_client.get("https://api.example.com/users")if err then return nil, errend
print(resp.status_code) -- 200print(resp.body) -- тело ответаPOST-запрос
Заголовок раздела «POST-запрос»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-запрос
Заголовок раздела «PUT-запрос»local resp, err = http_client.put("https://api.example.com/users/123", { headers = {["Content-Type"] = "application/json"}, body = json.encode({name = "Alice Smith"})})PATCH-запрос
Заголовок раздела «PATCH-запрос»local resp, err = http_client.patch("https://api.example.com/users/123", { body = json.encode({status = "active"})})DELETE-запрос
Заголовок раздела «DELETE-запрос»local resp, err = http_client.delete("https://api.example.com/users/123", { headers = {["Authorization"] = "Bearer " .. token}})HEAD-запрос
Заголовок раздела «HEAD-запрос»Возвращает только заголовки, без тела.
local resp, err = http_client.head("https://cdn.example.com/file.zip")local size = resp.headers["Content-Length"]Произвольный метод
Заголовок раздела «Произвольный метод»local resp, err = http_client.request("PROPFIND", "https://dav.example.com/folder", { headers = {["Depth"] = "1"}})| Параметр | Тип | Описание |
|---|---|---|
method | string | HTTP-метод |
url | string | URL запроса |
options | table | Опции запроса (опционально) |
Опции запроса
Заголовок раздела «Опции запроса»| Поле | Тип | Описание |
|---|---|---|
headers | table | Заголовки запроса {["Name"] = "value"} |
body | string | Тело запроса |
query | table | Query-параметры {key = "value"} |
form | table | Данные формы (Content-Type устанавливается автоматически) |
files | table | Загрузка файлов (массив определений файлов) |
cookies | table | Cookies запроса {name = "value"} |
auth | table | Basic-авторизация {user = "name", pass = "secret"} |
timeout | number/string | Таймаут: число в секундах или строка типа "30s", "1m" |
stream | boolean | Потоковое получение тела вместо буферизации |
max_response_body | number | Макс. размер ответа в байтах (0 = по умолчанию) |
unix_socket | string | Подключение через Unix-сокет |
tls | table | Настройки TLS для запроса (см. Параметры TLS) |
Query-параметры
Заголовок раздела «Query-параметры»local resp, err = http_client.get("https://api.example.com/search", { query = { q = "lua programming", page = "1", limit = "20" }})Заголовки и авторизация
Заголовок раздела «Заголовки и авторизация»local resp, err = http_client.get("https://api.example.com/data", { headers = { ["Authorization"] = "Bearer " .. token, ["Accept"] = "application/json" }})
-- Или через basic authlocal resp, err = http_client.get("https://api.example.com/data", { auth = {user = "admin", pass = "secret"}})Данные формы
Заголовок раздела «Данные формы»local resp, err = http_client.post("https://api.example.com/login", { form = { username = "alice", password = "secret123" }})Загрузка файлов
Заголовок раздела «Загрузка файлов»local resp, err = http_client.post("https://api.example.com/upload", { form = {title = "My Document"}, files = { { name = "attachment", -- имя поля формы filename = "report.pdf", -- исходное имя файла content = pdf_data, -- содержимое файла content_type = "application/pdf" } }})| Поле файла | Тип | Обязательно | Описание |
|---|---|---|---|
name | string | да | Имя поля формы |
filename | string | нет | Исходное имя файла |
content | string | да* | Содержимое файла |
reader | userdata | да* | Альтернатива: io.Reader для содержимого |
content_type | string | нет | MIME-тип (по умолчанию: application/octet-stream) |
*Требуется либо content, либо reader.
Таймаут
Заголовок раздела «Таймаут»-- Число: секундыlocal resp, err = http_client.get(url, {timeout = 30})
-- Строка: формат Go durationlocal 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
Заголовок раздела «Параметры TLS»Настройка TLS для отдельных запросов: mTLS (взаимный TLS) и пользовательские CA-сертификаты.
| Поле | Тип | Описание |
|---|---|---|
cert | string | Клиентский сертификат в формате PEM |
key | string | Закрытый ключ клиента в формате PEM |
ca | string | Пользовательский CA-сертификат в формате PEM |
server_name | string | Имя сервера для SNI-верификации |
insecure_skip_verify | boolean | Пропустить проверку TLS-сертификата |
Для mTLS необходимо указать оба поля cert и key. Поле ca заменяет системный пул сертификатов пользовательским CA.
Аутентификация mTLS
Заголовок раздела «Аутентификация mTLS»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, }})Пользовательский CA
Заголовок раздела «Пользовательский 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", }})Пропуск проверки TLS
Заголовок раздела «Пропуск проверки TLS»Пропуск TLS-верификации для сред разработки. Требует разрешение безопасности http_client.insecure_tls.
local resp, err = http_client.get("https://localhost:8443/api", { tls = { insecure_skip_verify = true, }})Объект ответа
Заголовок раздела «Объект ответа»| Поле | Тип | Описание |
|---|---|---|
status_code | number | HTTP-код статуса |
body | string | Тело ответа (если не потоковый) |
body_size | number | Размер тела в байтах (-1 если потоковый) |
headers | table | Заголовки ответа |
cookies | table | Cookies ответа |
url | string | Финальный URL (после редиректов) |
stream | Stream | Объект потока (если 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"])endПотоковые ответы
Заголовок раздела «Потоковые ответы»Для больших ответов используйте потоковый режим, чтобы не загружать всё тело в память.
local resp, err = http_client.get("https://cdn.example.com/large-file.zip", { stream = true})if err then return nil, errend
-- Обработка порциямиwhile true do local chunk, err = resp.stream:read(65536) if err or not chunk then break end -- обработка chunkendresp.stream:close()| Метод потока | Возвращает | Описание |
|---|---|---|
read(n?) | string, error | Читает до n байт (по умолчанию: буфер реализации) |
close() | boolean, error | Закрывает поток |
resp.stream — это полноценный объект stream: seek, stat и scanner также доступны.
Пакетные запросы
Заголовок раздела «Пакетные запросы»Выполнение нескольких запросов конкурентно.
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 -- Все успешны for i, resp in ipairs(responses) do print("Response " .. i .. ":", resp.status_code) endend| Параметр | Тип | Описание |
|---|---|---|
requests | table | Массив {method, url, options?} |
Возвращает: responses, errors — массивы, индексированные по позиции запроса
Замечания:
- Запросы выполняются конкурентно
- Потоковый режим (
stream = true) не поддерживается в пакетном режиме - Массивы результатов соответствуют порядку запросов (индексация с 1)
URL-кодирование
Заголовок раздела «URL-кодирование»Кодирование
Заголовок раздела «Кодирование»local encoded = http_client.encode_uri("hello world")-- "hello+world"
local url = "https://api.example.com/search?q=" .. http_client.encode_uri(query)Декодирование
Заголовок раздела «Декодирование»local decoded, err = http_client.decode_uri("hello+world")-- "hello world"Разрешения
Заголовок раздела «Разрешения»HTTP-запросы подчиняются вычислению политики безопасности.
Действия безопасности
Заголовок раздела «Действия безопасности»| Действие | Ресурс | Описание |
|---|---|---|
http_client.request | URL | Разрешить/запретить запросы к конкретным URL |
http_client.unix_socket | Путь сокета | Разрешить/запретить подключения через Unix-сокет |
http_client.private_ip | IP-адрес | Разрешить/запретить доступ к приватным IP-диапазонам |
http_client.insecure_tls | URL | Разрешить/запретить небезопасный TLS (пропуск верификации) |
Проверка доступа
Заголовок раздела «Проверка доступа»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")endЗащита от SSRF
Заголовок раздела «Защита от SSRF»Приватные IP-диапазоны (10.x, 192.168.x, 172.16-31.x, localhost) заблокированы по умолчанию. Доступ требует разрешения http_client.private_ip.
local resp, err = http_client.get("http://192.168.1.1/admin")-- Error: not allowed: private IP 192.168.1.1См. Модель безопасности для настройки политик.
| Условие | Kind | Повторяемо |
|---|---|---|
| Запрещено политикой безопасности | errors.PERMISSION_DENIED | нет |
| Приватный IP заблокирован | errors.PERMISSION_DENIED | нет |
| Unix-сокет запрещён | errors.PERMISSION_DENIED | нет |
| Небезопасный TLS запрещён | errors.PERMISSION_DENIED | нет |
| Некорректный URL или опции | errors.INVALID | нет |
| Нет контекста | errors.INTERNAL | нет |
| Сетевая ошибка | errors.INTERNAL | да |
| Таймаут | errors.INTERNAL | да |
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, errendСм. Обработка ошибок для работы с ошибками.