コンテンツにスキップ

HTTPクライアント

外部サービスへのHTTPリクエストを行う。すべてのHTTPメソッド、ヘッダー、クエリパラメータ、フォームデータ、ファイルアップロード、ストリーミングレスポンス、並行バッチリクエストをサポート。

local http_client = require("http_client")

すべてのメソッドは同じシグネチャを共有: method(url, options?)Response, error を返す。

local resp, err = http_client.get("https://api.example.com/users")
if err then
return nil, err
end
print(resp.status_code) -- 200
print(resp.body) -- レスポンスボディ
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"})
})
local resp, err = http_client.put("https://api.example.com/users/123", {
headers = {["Content-Type"] = "application/json"},
body = json.encode({name = "Alice Smith"})
})
local resp, err = http_client.patch("https://api.example.com/users/123", {
body = json.encode({status = "active"})
})
local resp, err = http_client.delete("https://api.example.com/users/123", {
headers = {["Authorization"] = "Bearer " .. token}
})

ヘッダーのみを返し、ボディなし。

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"}
})
パラメータ説明
methodstringHTTPメソッド
urlstringリクエストURL
optionstableリクエストオプション(オプション)
フィールド説明
headerstableリクエストヘッダー {["Name"] = "value"}
bodystringリクエストボディ
querytableクエリパラメータ {key = "value"}
formtableフォームデータ(Content-Typeを自動設定)
filestableファイルアップロード(ファイル定義の配列)
cookiestableリクエストCookie {name = "value"}
authtableBasic認証 {user = "name", pass = "secret"}
timeoutnumber/stringタイムアウト: 秒数または "30s", "1m" のような文字列
streambooleanバッファリングせずにレスポンスボディをストリーミング
max_response_bodynumber最大レスポンスサイズ(バイト単位)(0 = デフォルト)
unix_socketstringUnixソケットパス経由で接続
tlstableリクエストごとのTLS設定(TLSオプションを参照)
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認証を使用
local 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"
}
}
})
ファイルフィールド必須説明
namestringyesフォームフィールド名
filenamestringno元のファイル名
contentstringyes*ファイル内容
readeruserdatayes*代替: 内容用のio.Reader
content_typestringnoMIMEタイプ(デフォルト: application/octet-stream

*contentまたはreaderのいずれかが必須。

-- 数値: 秒
local resp, err = http_client.get(url, {timeout = 30})
-- 文字列: Go duration形式
local 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設定で、mTLS(相互TLS)やカスタムCA証明書を構成する。

フィールド説明
certstringPEM形式のクライアント証明書
keystringPEM形式のクライアント秘密鍵
castringPEM形式のカスタムCA証明書
server_namestringSNI検証用のサーバー名
insecure_skip_verifybooleanTLS証明書検証をスキップ

mTLSにはcertkeyの両方を一緒に指定する必要がある。caフィールドはシステム証明書プールをカスタムCAで上書きする。

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,
}
})
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検証をスキップする。http_client.insecure_tlsセキュリティ権限が必要。

local resp, err = http_client.get("https://localhost:8443/api", {
tls = {
insecure_skip_verify = true,
}
})
フィールド説明
status_codenumberHTTPステータスコード
bodystringレスポンスボディ(ストリーミングでない場合)
body_sizenumberボディサイズ(バイト単位)(ストリーミング時は-1)
headerstableレスポンスヘッダー
cookiestableレスポンスCookie
urlstring最終URL(リダイレクト後)
streamStreamStreamオブジェクト(stream = trueの場合)
local resp, err = http_client.get("https://api.example.com/data")
if err then
return nil, err
end
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, err
end
-- チャンクで処理
while true do
local chunk, err = resp.stream:read(65536)
if err or not chunk then break end
-- チャンクを処理
end
resp.stream:close()
Streamメソッド戻り値説明
read(n?)string, error最大nバイトを読み取り(デフォルト: 実装のバッファ)
close()boolean, errorストリームを閉じる

resp.stream は完全な stream オブジェクトです — seekstatscanner も利用できます。

複数のリクエストを並行して実行。

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
end
else
-- すべて成功
for i, resp in ipairs(responses) do
print("Response " .. i .. ":", resp.status_code)
end
end
パラメータ説明
requeststable{method, url, options?}の配列

戻り値: responses, errors - リクエスト位置でインデックス付けされた配列

注意:

  • リクエストは並行して実行される
  • ストリーミング(stream = true)はバッチではサポートされない
  • 結果配列はリクエスト順序に一致(1インデックス)
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.requestURL特定のURLへのリクエストを許可/拒否
http_client.unix_socketソケットパスUnixソケット接続を許可/拒否
http_client.private_ipIPアドレスプライベートIP範囲へのアクセスを許可/拒否
http_client.insecure_tlsURL安全でない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

プライベート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

ポリシー設定についてはセキュリティモデルを参照。

条件種別再試行可能
セキュリティポリシーが拒否errors.PERMISSION_DENIEDno
プライベートIPがブロックerrors.PERMISSION_DENIEDno
Unixソケットが拒否errors.PERMISSION_DENIEDno
安全でないTLSが拒否errors.PERMISSION_DENIEDno
無効なURLまたはオプションerrors.INVALIDno
コンテキストがないerrors.INTERNALno
ネットワーク障害errors.INTERNALyes
タイムアウトerrors.INTERNALyes
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, err
end

エラーの処理についてはエラー処理を参照。