px普贤教程PuXian
普贤教程 › 进阶教程

HTTP 客户端

HTTP 客户端只有两个入口:http_get 拿响应体,http_request 拿到完整响应(状态码、头、体)。

http_get:只要内容

px
var html = http_get("https://cx.dzty.club/")
print(type(html))
print(str(len(html) > 0))
text
string
true

返回的是响应体字符串,状态码被丢掉。只适合"一定能拿到内容"的场景,比如抓一个公开页面。

http_request:完整响应

px
var r = http_request("https://cx.dzty.club/", "GET", null)
print(str(r["status"]))
print(str(r["headers"].keys()))
print(str(len(r["body"]) > 0))
text
200
[content-type, date, server, ...]
true
参数说明
url完整 URL,含 http(s) 前缀
method"GET" / "POST" / "PUT" / "DELETE"
body请求体字符串;GET 传 null
headers可选,字典,如 {"Content-Type": "application/json"}

返回字典:{"status": int, "headers": dict, "body": string}。

POST JSON

px
var payload = json_stringify({"name": "晨曦", "action": "ping"})
var r = http_request("https://cx.dzty.club/api/v1/ping", "POST", payload,
    {"Content-Type": "application/json"})
print(str(r["status"]))
text
200
Header 大小写请求头的键按习惯写 Content-Type;响应头的键名由服务端决定,读的时候用 r["headers"].has("Content-Type") 判断存在,别假设一定叫某个拼写。Set-Cookie 出现多次时会以 list 形式返回。

判读状态码

http_request 不把 4xx / 5xx 当失败——只要拿到响应就返回。业务上要自己判:

px
def fetch_json(url):
    var r = http_request(url, "GET", null)
    if r["status"] < 200 or r["status"] >= 300:
        return Err("HTTP " + str(r["status"]))
    var parsed = json_parse_opt(r["body"])
    if parsed.is_err():
        return Err("响应不是 JSON:" + parsed.err())
    return Ok(parsed.ok())

var res = fetch_json("https://cx.dzty.club/api/v1/me")
if res.is_err():
    print(res.err())
else:
    print("ok")

超时与重试

网络调用必须设上限。默认超时可能很长,写服务时自己包一层重试:

px
def get_with_retry(url, times):
    var i = 0
    var last = ""
    while i < times:
        var r = http_request(url, "GET", null)
        if r["status"] >= 200 and r["status"] < 300:
            return Ok(r["body"])
        last = "HTTP " + str(r["status"])
        i += 1
    return Err("重试 " + str(times) + " 次仍失败:" + last)

print(str(get_with_retry("https://cx.dzty.club/", 2).is_ok()))
text
true

并发请求

要同时打多个地址,必须在编译轨用 spawn(解释器不支持并发):

px
# 需 px build 后运行
var ch = chan [dict](3)
var urls = ["https://a.example/", "https://b.example/", "https://c.example/"]
for u in urls:
    spawn worker(u, ch)
var i = 0
while i < 3:
    print(str(ch.recv()["status"]))
    i += 1

与 Ma 托管的接口通信

同一台机器内部调用,走回环地址,别绕到公网域名:

px
var r = http_request("http://127.0.0.1:9536/api/v1/sync/status", "GET", null)
print(str(r["status"]))
给请求加标识内部服务之间调用时带上 X-Request-Id,日志里能串起一整条链路;排查"哪个环节慢/错"时省一半时间。

常见问题

现象原因
返回体为空服务端 3xx 重定向,客户端不自动跟随
403 / 406缺 User-Agent 或 Referer,按服务端要求补头
中文乱码响应头 charset 与实际编码不一致
偶发超时没有重试;或对端连接池耗尽