HOOZi文档
Skip to content

net

HTTP + WebSocket。全异步 —— 回调在菜单线程派发,Lua 安全,可直接 gui.set / notify.*。同步 API(get_sync 之类)不提供,会阻塞菜单线程。

生命周期

资源卸载行为
HTTP 待回调(net.http:*排队中的 response 静默丢弃,不调你的回调
WebSocket 客户端(net.ws:connect该脚本打开的连接全部关闭
WebSocket server(net.ws_server:listen该脚本打开的 server 全部关闭,所有 client 强制断开

WS 客户端连不上 server 时(端口关、超时、URL 错)后台资源自动清理,反复重连不会泄漏内存或线程。net.ws:connect 是即发即忘风格 —— 不需要每次失败手动 :close,可以放心放循环里 retry。


net.http

resp 回调参数字段:status : int, body : string, error : string, ok : bool

net.http:get(url, callback, timeout?)

参数url : string, callback : function(resp), timeout? : int = 10(秒)

net.http:get(url, options, callback) — 带 headers / 文件下载

参数url : string, options : table, callback : function(resp)

net.http:post(url, body, content_type, callback, timeout?)

参数url : string, body : string, content_type : string, callback : function(resp), timeout? : int = 10

net.http:post(url, options, callback) — 带 headers / 自定义 body

参数url : string, options : table, callback : function(resp)

net.http:request(url, method, options, callback) — 任意 method

参数url : string, method : string(GET / POST / PUT / DELETE / PATCH 等), options : table, callback : function(resp)

options 表可选字段:

字段类型说明
headerstable<string,string>自定义请求头
bodystring请求体(GET 可空)
content_typestring自动合成 Content-Type
save_to_filestring非空时流式写文件而非 resp.body(大文件下载用,沙盒外路径)
timeoutint秒,默认 10

net.ws

net.ws:connect(url, callbacks) → ws_id : int

参数url : string, callbacks : table

callbacks 表中可选字段(每个都是 function):

字段签名
on_openfunction(id : int)
on_messagefunction(id : int, msg : string)
on_errorfunction(id : int, err : string)
on_closefunction(id : int, code : int, reason : string)

net.ws:send(id, msg) → bool

net.ws:close(id)

net.ws:is_open(id) → bool


net.ws_server

WebSocket 服务端。仅监听 127.0.0.1(本机 web dashboard / IPC,不开外网)。 脚本卸载时该脚本创建的全部 server 自动关闭,所有 client 强制断开。

net.ws_server:listen(port, callbacks) → WsServer | nil

参数

  • port : int — 本机端口(被占用返 nil)
  • callbacks : table — 回调表
字段签名说明
on_openfn(client : int)新 client 完成 handshake
on_messagefn(client : int, msg : string)收到文本 / 二进制消息
on_errorfn(client : int, err : string)异常
on_closefn(client : int, code : int, reason : string)client 断开(含远端主动关或本端断)

返回 WsServer userdata(失败 nil)。

WsServer 方法

方法说明
srv:send(client, msg) → bool给指定 client 发文本消息
srv:broadcast(msg)给该 server 所有 client 广播
srv:disconnect(client, code?, reason?)主动断指定 client;code 默认 1000,reason 默认空
srv:close()关 server + 全部 client + join 内部线程
srv:is_open() → boolserver 是否仍在运行
srv:client_count() → int当前已连接 client 数
srv.idserver 数字 id(read-only)

约束

  • 64MB 单消息上限(防恶意大 payload)
  • text (opcode 0x1) 发出方向;text / binary 都能接收
  • 不支持 wss://(TLS) —— 本机用例不需要
  • 不支持 fragmented frame 跨 opcode 的 subprotocol
  • 自动响应 ping → pong,不触发用户回调
lua
-- 本机 dashboard:8080 端口,浏览器接 ws://127.0.0.1:8080/
local srv = net.ws_server:listen(8080, {
    on_open    = function(c) print("client", c, "joined") end,
    on_message = function(c, msg) print("got from", c, ":", msg) end,
    on_close   = function(c, code, reason) print("client", c, "left", code) end,
})

if not srv then return end

-- 每帧广播游戏状态
event.on("frame_update", function(e)
    local lp = game.localplayer
    if lp then
        srv:broadcast(json.encode({hp=lp.health, sh=lp.shield, vel=lp.abs_velocity}))
    end
end)

-- 收命令对应处理
event.on("script_unloaded", function(ue)
    if ue.script_path == _SCRIPT_PATH then srv:close() end
end)

示例

lua
-- HTTP GET(异步)
net.http:get("https://example.com", function(resp)
    if resp.ok then
        log.info("OK " .. resp.status .. ", body len=" .. #resp.body)
    else
        log.warn("HTTP fail: " .. (resp.error or ""))
    end
end, 3)

-- HTTP POST JSON(旧签名)
net.http:post("https://api.example.com/log",
    [[{"event":"hello"}]], "application/json",
    function(resp) print(resp.status, resp.ok) end, 5)

-- 带 Authorization 的 GET(options 风格)
net.http:get("https://api.example.com/me", {
    headers = { ["Authorization"] = "Bearer " .. token, ["X-Trace-Id"] = "abc" },
    timeout = 5,
}, function(resp) log.info(resp.body) end)

-- POST JSON 带自定义 header
net.http:post("https://api.example.com/log", {
    headers = { ["Authorization"] = "Bearer " .. token },
    body = json.encode({ event = "hello" }),
    content_type = "application/json",
}, function(resp) print(resp.status) end)

-- 大文件下载到本地(不占内存)
net.http:get("https://example.com/big.zip", {
    save_to_file = "downloads/big.zip",
    timeout = 60,
}, function(resp) log.info("downloaded, status=" .. resp.status) end)

-- PUT / DELETE
net.http:request("https://api.example.com/item/42", "DELETE", {
    headers = { ["Authorization"] = "Bearer " .. token },
}, function(resp) print(resp.ok) end)

-- WebSocket 4 回调
local ws_id = net.ws:connect("wss://echo.example.com", {
    on_open    = function(id) net.ws:send(id, "hi") end,
    on_message = function(id, msg) log.info("recv " .. msg) end,
    on_error   = function(id, err) log.warn("err " .. err) end,
    on_close   = function(id, code, reason) log.info("close " .. code) end,
})