Skip to content

HTTP 客户端(http) ​

发送 HTTP / HTTPS 请求。模块名 http 是协议名,没有拼音名;函数有拼音名。

cpro
daoru "http"

rukou() {
    changshi {
        bl r = http.huoqu("https://example.com/")
        dayin(r.status_code)
        dayin(http.wenben(&r))
    } buhuo (e) {
        dayin(e.xinxi)
    }
}
cpro
import "http"

rukou() {
    try {
        var r = http.get("https://example.com/")
        print(r.status_code)
        print(http.text(&r))
    } catch (e) {
        print(e.msg)
    }
}

先安装 libcurl ​

http 模块基于 libcurl,cpro 不自带,要先装好:

系统安装
Ubuntu / Debiansudo apt install libcurl4-openssl-dev
Windows(MSYS2 UCRT64)pacman -S mingw-w64-ucrt-x86_64-curl

只有导入了 http 的程序才需要 libcurl。没装时会在链接时报 cannot find -lcurl。

在 Windows 上把程序发给别人时,要把 libcurl 的 DLL 一起带上。

函数一览 ​

拼音英文签名说明
huoquget(url zifuchuan, opt 选项 = {}) 响应 kecuoGET 请求
tijiaopost(url zifuchuan, body [w8], opt 选项 = {}) 响应 kecuoPOST 字节
tijiao_wenbenpost_string(url zifuchuan, body zifuchuan, opt 选项 = {}) 响应 kecuoPOST 文本
toubuheader(r &响应, name zifuchuan) kexuan(zifuchuan)取第一个同名响应头
toubu_quanbuheader_all(r &响应, name zifuchuan) [zifuchuan]取所有同名响应头
wenbentext(r &响应) zifuchuan kecuo响应体转成文本

请求选项 ​

三个选项都有默认值,传参时写一个不带类型名的结构体字面量,只写要改的字段:

字段默认值说明
headers[]请求头,每个元素一行 "Name: value"
timeout_ms30000整个请求的总时长(毫秒),0 表示不限
verify_tlstrue是否校验 HTTPS 证书
cpro
daoru "http"

rukou() {
    bl body = "{\"name\":\"cpro\"}"
    changshi {
        bl r = http.tijiao_wenben("https://example.com/api", body, {
            headers: ["Content-Type: application/json"],
            timeout_ms: 10000,
        })
        dayin(r.status_code)
    } buhuo (e) {
        dayin(e.xinxi)
    }
}
cpro
import "http"

rukou() {
    var body = "{\"name\":\"cpro\"}"
    try {
        var r = http.post_string("https://example.com/api", body, {
            headers: ["Content-Type: application/json"],
            timeout_ms: 10000,
        })
        print(r.status_code)
    } catch (e) {
        print(e.msg)
    }
}
  • POST 时请自己设置 Content-Type,不设时默认是 application/x-www-form-urlencoded,发 JSON 很可能被服务端拒绝
  • 请求头里不能含换行符,否则报错(防止请求头注入)
  • verify_tls: false 只用于自签名证书的测试环境,不要用在正式代码里
  • timeout_ms 是从连接到收完响应的总时长,下载大文件时可能需要调大

响应 ​

响应的三个字段可以直接读,字段名只有英文:

字段类型说明
r.status_codez64状态码,如 200、404
r.headers[zifuchuan]响应头,每个元素一行 "Name: value"
r.body[w8]响应体的原始字节

4xx / 5xx 不是错误。只要服务端返回了响应,请求就算成功,状态码由你自己判断。进入 buhuo 表示请求本身没完成(连不上、超时、证书错误等):

cpro
changshi {
    bl r = http.huoqu("https://example.com/user/1")
    ruguo (r.status_code == 200) {
        dayin(http.wenben(&r))
    } fouze ruguo (r.status_code == 404) {
        dayin("用户不存在")
    } fouze {
        dayin("服务端返回", r.status_code)
    }
} buhuo (e) {
    dayin("请求失败:", e.xinxi)
}
cpro
try {
    var r = http.get("https://example.com/user/1")
    if (r.status_code == 200) {
        print(http.text(&r))
    } else if (r.status_code == 404) {
        print("用户不存在")
    } else {
        print("服务端返回", r.status_code)
    }
} catch (e) {
    print("请求失败:", e.msg)
}

查响应头用 toubu,头名不区分大小写:

cpro
bl ct = http.toubu(&r, "content-type")
ruguo (ct != kong) {
    dayin(jiebao(ct, ""))
}
cpro
var ct = http.header(&r, "content-type")
if (ct != none) {
    print(unwrap(ct, ""))
}

Set-Cookie 这类会重复出现的头,用 toubu_quanbu。

wenben 只认 UTF-8,GBK 等编码的页面会报错。图片等二进制内容直接用 r.body,可以用 文件模块 的 xie_zijie 存盘。

和文件句柄不同,响应可以复制、可以放进数组;但它的类型名同样用不了,要交给别的函数处理时,请传需要的字段(如 r.status_code、r.body)。

不会自动做的事 ​

不跟随重定向:遇到 301、302 等,直接返回这个响应。要跳转就自己读 Location 头再请求一次:

cpro
hs get_follow(url zifuchuan) [w8] kecuo {
    bl r = sp_kecuo http.huoqu(url)
    ruguo (r.status_code >= 300 && r.status_code < 400) {
        bl loc = http.toubu(&r, "location")
        ruguo (loc != kong) {
            r = sp_kecuo http.huoqu(jiebao(loc, ""))
        }
    }
    fanhui r.body
}
cpro
fn get_follow(url string) [u8] fails {
    var r = up_fails http.get(url)
    if (r.status_code >= 300 && r.status_code < 400) {
        var loc = http.header(&r, "location")
        if (loc != none) {
            r = up_fails http.get(unwrap(loc, ""))
        }
    }
    return r.body
}

不管 Cookie:不保存,也不自动发送。需要时从 Set-Cookie 响应头里读出来,下次请求自己放进 headers。

不编码 URL:URL 里的中文、空格请自己按百分号编码好再传。只支持 http:// 和 https://。

错误码 ​

0–10 和 TCP 的含义相同,11 起是 HTTP 特有的:

错误码含义判断函数
1连接被拒绝shi_jujue / is_refused
2超时shi_chaoshi / is_timeout
3主机不可达或域名解析失败shi_bu_keda / is_unreachable
4、5连接被重置或对方已关闭shi_yi_guanbi / is_closed
9读写出错,或 wenben 遇到非 UTF-8 内容—
11请求不合法:URL 错误、协议不支持、请求头含换行—
12TLS 握手失败shi_woshou_shibai / is_tls
13证书校验失败shi_zhengshu_cuowu / is_cert
14服务端的响应不符合 HTTP 协议—

请用 http 自己的判断函数,不要用 wangluo 的。

cpro
changshi {
    bl r = http.huoqu("https://example.com/")
} buhuo (e) {
    ruguo (http.shi_chaoshi(e.daima)) {
        dayin("请求超时,请稍后再试")
    } fouze ruguo (http.shi_zhengshu_cuowu(e.daima)) {
        dayin("证书校验失败:", e.xinxi)
    } fouze {
        dayin(e.xinxi)
    }
}
cpro
try {
    var r = http.get("https://example.com/")
} catch (e) {
    if (http.is_timeout(e.code)) {
        print("请求超时,请稍后再试")
    } else if (http.is_cert(e.code)) {
        print("证书校验失败:", e.msg)
    } else {
        print(e.msg)
    }
}

证书校验失败(13)的常见原因:服务端用的是自签名证书、证书过期或域名不匹配,或者本机缺少 CA 证书(Ubuntu 上安装 ca-certificates)。

暂不支持 ​

  • PUT、DELETE、PATCH、HEAD 请求
  • 连接复用、并发请求
  • 流式下载、上传进度
  • 指定代理(会读取 http_proxy / https_proxy 环境变量)、指定 CA 证书文件

cpro 目前处于测试阶段