httpplus - http核心库的补充
作者:朱天华
一、概述
HTTP 在如下的场景,开发成本是最低的:
1、终端和云端交换文件,不用开发复杂的分包组包协议;
2、终端从云端下载各种参数,或者终端向云端提交各种参数, 不用设计报文协议,用http 的参数即可,非常方便。
LuatOS提供了http核心库和httpplus扩展库实现了http客户端
http核心库和httpplus扩展库的区别如下:
区别项 | http核心库 | httpplus扩展库 |
---|---|---|
文件上传 | 文件最大64KB | 只要内存够用,文件大小不限 |
文件下载 | 支持,只要文件系统空间够用,文件大小不限 | 不支持 |
http header的key:value的限制 | 所有header的value总长度不能超过4KB, 单个header的value长度不能超过1KB |
只要内存够用,header长度不限 |
鉴权URL自动识别 | 不支持 | 支持 |
接收到的body数据存储支持zbuff | 不支持 | 支持,可以直接传输给uart等库 |
接收到的body数据存储到内存中 | 最大支持32KB | 只要内存够用,大小不限 |
chunk编码 | 支持 | 不支持 |
本篇文章仅介绍httpplus扩展库,如果需要了解http核心库,请 点击此处
二、核心示例
1、核心示例是指:使用本库文件提供的核心API,开发的基础业务逻辑的演示代码;
2、核心示例的作用是:帮助开发者快速理解如何使用本库,所以核心示例的逻辑都比较简单;
3、更加完整和详细的demo,请参考 LuatOS仓库 中各个产品目录下的demo/http
-- 普通的http get请求功能演示
-- 请求的body数据保存到内存变量中,在内存够用的情况下,长度不限
-- timeout可以设置超时时间
local function httpplus_app_get()
local body
-- https get请求https://www.air32.cn/网页内容
-- 如果请求成功,请求的数据保存到response.body中
local code, response = httpplus.request({url="https://www.air32.cn/"})
log.info("httpplus_app_get1", code==200 and "success" or "error", code)
if code==200 then
log.info("httpplus_app_get1 headers", json.encode(response.headers or {}))
body = response.body:query()
log.info("httpplus_app_get1 body", body and (body:len()>512 and body:len() or body) or "nil")
end
-- http get请求http://httpbin.air32.cn/get网页内容,超时时间为3秒
-- 请求超时时间为3秒,用户自己写代码时,不要照抄3秒,根据自己业务逻辑的需要设置合适的超时时间
-- 如果请求成功,请求的数据保存到body中
code, response = httpplus.request({url="http://httpbin.air32.cn/get", timeout=3})
log.info("httpplus_app_get2", code==200 and "success" or "error", code)
if code==200 then
log.info("httpplus_app_get2 headers", json.encode(response.headers or {}))
body = response.body:query()
log.info("httpplus_app_get2 body", body and (body:len()>512 and body:len() or body) or "nil")
end
end
-- http app task 的任务处理函数
local function httpplus_app_task_func()
while true do
-- 如果当前时间点设置的默认网卡还没有连接成功,一直在这里循环等待
while not socket.adapter(socket.dft()) do
log.warn("httpplus_app_task_func", "wait IP_READY", socket.dft())
-- 在此处阻塞等待默认网卡连接成功的消息"IP_READY"
-- 或者等待1秒超时退出阻塞等待状态;
-- 注意:此处的1000毫秒超时不要修改的更长;
-- 因为当使用exnetif.set_priority_order配置多个网卡连接外网的优先级时,会隐式的修改默认使用的网卡
-- 当exnetif.set_priority_order的调用时序和此处的socket.adapter(socket.dft())判断时序有可能不匹配
-- 此处的1秒,能够保证,即使时序不匹配,也能1秒钟退出阻塞状态,再去判断socket.adapter(socket.dft())
sys.waitUntil("IP_READY", 1000)
end
-- 检测到了IP_READY消息
log.info("httpplus_app_task_func", "recv IP_READY", socket.dft())
-- 普通的http get请求功能演示
httpplus_app_get()
-- 60秒之后,循环测试
sys.wait(60000)
end
end
--创建并且启动一个task
--运行这个task的处理函数httpplus_app_task_func
sys.taskInit(httpplus_app_task_func)
三、常量详解
核心库常量,顾名思义是由合宙LuatOS内核固件中定义的、不可重新赋值或修改的固定值,在脚本代码中不需要声明,可直接调用;
httpplus扩展库没有常量。
四、函数详解
httpplus.request(opts)
功能
http 客户端,发送http请求到服务器,并且接收服务器应答;
只能在task中使用,会阻塞当前task,等待整个过程成功结束或者出现错误异常结束或者超时结束,超时时长和opts.timeout有
参数
opts
参数含义:HTTP请求的参数配置;参数为table类型,table内容格式说明如下:
{
-- 参数含义:HTTP请求的URL地址;
-- 数据类型:string;
-- 取值范围:支持HTTP、HTTPS,支持域名、IP地址,支持自定义端口,标准的HTTP URL格式都支持;
-- 是否必选:必须传入此参数;
-- 注意事项:暂无;
-- 参数示例:"https://www.luatos.com/"
url = ,
-- 参数含义:HTTP请求方法;
-- 数据类型:string;
-- 取值范围:支持"GET"、"POST"、"HEAD"等所有HTTP请求方法,请求方法用大写字母表示;
-- 是否必选:可选传入此参数;如果没有传入此参数或者传入了nil类型,则使用默认值,默认值分为以下两种情况:
-- 如果没有设置files,forms,body,bodyfile参数,则默认为"GET"
-- 如果至少设置了files,forms,body,bodyfile中的一种参数,则默认为"POST"
-- 注意事项:暂无;
-- 参数示例:GET请求时填"GET",POST请求时填"POST";
method = ,
-- 参数含义:HTTP请求头列表,键值对的形式;
-- 数据类型:table或者nil;
-- 取值范围:当为table数据类型时,请求头列表中支持一个或者多个请求头;
-- 是否必选:可选传入此参数;
-- 注意事项:暂无;
-- 参数示例:{
-- ["Content-Type"] = "application/x-www-form-urlencoded",
-- ["self_defined_key"] = "self_defined_value"
-- }
headers = ,
-- 参数含义:HTTP POST上传的文件列表,键值对的形式;
-- 数据类型:table或者nil;
-- 取值范围:当为table数据类型时,文件列表中支持一个或者多个文件;
-- 是否必选:可选传入此参数;
-- 注意事项:若存在本参数,会自动强制以multipart/form-data形式上传;
-- 参数示例:{
-- ["uploadFile"] = "/luadb/logo.jpg",
-- ["logo1.jpg"] = "/luadb/logo.jpg",
-- }
files = ,
-- 参数含义:HTTP POST上传的表单参数列表,键值对的形式;
-- 数据类型:table或者nil;
-- 取值范围:当为table数据类型时,文件列表中支持一个或者多个文件;
-- 是否必选:可选传入此参数;
-- 注意事项:若存在本参数并且不存在files参数,会自动强制以application/x-www-form-urlencoded形式上传;
-- 若存在本参数并且存在files参数,会自动强制以multipart/form-data形式上传,也就是说支持同时上传文件和表单参数;
-- 参数示例:{
-- ["username"] = "LuatOS",
-- ["password"] = "123456",
-- }
forms = ,
-- 参数含义:HTTP请求体;
-- 数据类型:string或者zbuff或者nil;
-- 取值范围:无特别限制;
-- 是否必选:可选传入此参数;
-- 注意事项:不能与files或者forms同时存在;
-- 参数示例:"123456" 或者 一个zbuff对象 或者 nil
body = ,
-- 参数含义:要上传的一个文件的完整路径;
-- 数据类型:string或者nil;
-- 取值范围:无特别限制;
-- 是否必选:可选传入此参数;
-- 注意事项:会自动读取文件中的内容进行上传;
-- 不能与files或者forms同时存在;
-- 可以与body同时存在,与body同时存在时, 优先级高于body参数,也就是说,bodyfile对应的文件路径中的内容在body参数对应的内容之前;
-- 参数示例:"/luadb/logo.jpg"
bodyfile = ,
-- 参数含义:是否打开debug调试信息日志的开关;
-- 数据类型:boolean或者nil;
-- 取值范围:boolean类型时,true表示打开,false表示关闭;
-- 是否必选:可选传入此参数,默认值为false;
-- 注意事项:暂无;
-- 参数示例:false;
debug = ,
-- 参数含义:HTTP请求过程中是否优先尝试ipv6;
-- 数据类型:boolean或者nil;
-- 取值范围:boolean类型时,true表示优先尝试ipv6;false表示不尝试ipv6,直接使用ipv4;
-- 是否必选:可选传入此参数,默认值为false;
-- 注意事项:如果优先尝试ipv6,ipv6失败后,会自动再尝试ipv4;
-- 参数示例:false;
try_ipv6 = ,
-- 参数含义:从发送请求到收到服务器响应,整个过程的超时时长,单位秒;
-- 数据类型:number或者nil;
-- 取值范围:number类型时,取值范围为大于等于0的整数,0表示永久等待;
-- 是否必选:可选传入此参数,默认值为30秒;
-- 注意事项:暂无;
-- 参数示例:20表示超时时长20秒;
timeout = ,
-- 参数含义:上网使用的网卡ID;
-- 数据类型:number或者nil;
-- 取值范围:number类型时,取值范围参考socket api中的常量详解;
-- 是否必选:可选传入此参数;
-- 注意事项:如果没有传入此参数,内核固件会自动选择当前时间点其他功能模块设置的默认网卡;
-- 除非你HTTP请求时,一定要使用某一种网卡,才设置此参数;
-- 如果没什么特别要求,不要设置此参数,使用系统中设置的默认网卡即可 ;
-- 一般来说,LuatOS的网络应用demo中都会有netdrv_device功能模块设置默认网卡;
-- 所以建议使用http.request接口时,不要设置此参数,直接使用netdrv_device设置的默认网卡就行;
-- 参数示例:socket.LWIP_GP表示使用4G网卡;
adapter = ,
}
数据类型:table或者nil;
取值范围:参考参数含义内各字段说明
是否必选:可选传入此参数;
注意事项:暂无;
参数示例:url为"http://httpbin.air32.cn/get";超时3秒:
{
url="http://httpbin.air32.cn/get",
timeout=3
}
method为"POST";url为"http://httpbin.air32.cn/post";自定义请求头为{["my_key"] = "my_value"};请求body为"This is a raw text message from LuatOS device":
{
method = "POST",
url = "http://httpbin.air32.cn/post",
headers = {["Content-Type"] = "text/plain"},
body = "This is a raw text message from LuatOS device"
}
返回值
local code, response = httpplus.request(opts)
code
含义说明:HTTP请求的执行结果;
数据类型:number;
取值范围:大于等于100或者小于0;
大于等于100时,表示服务器返回的HTTP状态码,例如200表示成功,详细说明可以通过搜索引擎搜索“HTTP状态码”自行了解;
小于0时,表示内核固件中检测到通信异常,有如下几种
-1:HTTP_ERROR_STATE,错误的状态, 一般是底层异常,如果出现此问题,可以联系合宙技术人员报issue解决;
-2:HTTP_ERROR_HEADER,错误的响应头部, 通常是服务器问题;
-3:HTTP_ERROR_BODY,错误的响应体,通常是服务器问题;
-4:HTTP_ERROR_CONNECT,连接服务器失败, 未联网,地址错误,域名错误等问题;
-5:HTTP_ERROR_CLOSE,提前断开了连接, 网络或服务器问题;
-6:HTTP_ERROR_RX,接收数据报错, 网络问题;
-7:HTTP_ERROR_DOWNLOAD,下载文件过程报错, 网络问题或下载路径问题;
-8:HTTP_ERROR_TIMEOU, 超时, 包括连接超时,发送数据超时,接收数据超时;
-9:HTTP_ERROR_FOTA,使用此接口下载升级包时,fota功能报错,通常是更新包不合法;
注意事项:暂无;
返回示例:例如200就表示请求成功;
response
含义说明:HTTP请求的应答数据;参数为table类型时,table内容格式说明如下:
{
-- 含义说明:HTTP应答头列表,键值对的形式;
-- 数据类型:table;
-- 取值范围:应答头列表中支持一个或者多个应答头;
-- 注意事项:暂无;
-- 返回示例:{
-- ["Content-Length"] = "265",
-- ["Date"] = "Sat, 30 Aug 2025 01",
-- ["Connection"] = "close",
-- ["Content-Type"] = "application/json"
-- }
headers = ,
-- 参数含义:HTTP应答体;
-- 数据类型:zbuff;
-- 取值范围:无特别限制;
-- 注意事项:通过zbuff的query函数,可以转化为string类型:response.body:query();
-- 也可以通过uart.tx等支持zbuff的函数直接使用,例如uart.tx(1, response.body);
-- 返回示例:一个zbuff对象;
body = ,
}
数据类型:table或者nil;
取值范围:当code的返回值大于等于100时,response表示请求到的数据内容,table类型,具体内容参考含义说明;
当code的返回值小于0时,response为nil
注意事项:暂无;
返回示例:超时3秒;接收的body数据保存到"/http_download/logo.jpg"中;接收数据过程中,回调函数为http_cbfunc,回调函数的回调参数为"download_logo":
{
headers =
{
["Content-Length"] = "265",
["Date"] = "Sat, 30 Aug 2025 01",
["Connection"] = "close",
["Content-Type"] = "application/json"
},
body = 此处是一个zbuff对象
}
示例
本示例章节仅列举一些常用功能的核心代码片段
更加完整和详细的demo,请参考 https://gitee.com/openLuat/LuatOS/tree/master/module 各个产品目录下的demo/http下的httpplus_app.lua
-- 普通的http get请求功能演示
-- 请求的body数据保存到内存变量中,在内存够用的情况下,长度不限
-- timeout可以设置超时时间
local function httpplus_app_get()
local body
-- https get请求https://www.air32.cn/网页内容
-- 如果请求成功,请求的数据保存到response.body中
local code, response = httpplus.request({url="https://www.air32.cn/"})
log.info("httpplus_app_get1", code==200 and "success" or "error", code)
if code==200 then
log.info("httpplus_app_get1 headers", json.encode(response.headers or {}))
body = response.body:query()
log.info("httpplus_app_get1 body", body and (body:len()>512 and body:len() or body) or "nil")
end
-- http get请求http://httpbin.air32.cn/get网页内容,超时时间为3秒
-- 请求超时时间为3秒,用户自己写代码时,不要照抄3秒,根据自己业务逻辑的需要设置合适的超时时间
-- 如果请求成功,请求的数据保存到body中
code, response = httpplus.request({url="http://httpbin.air32.cn/get", timeout=3})
log.info("httpplus_app_get2", code==200 and "success" or "error", code)
if code==200 then
log.info("httpplus_app_get2 headers", json.encode(response.headers or {}))
body = response.body:query()
log.info("httpplus_app_get2 body", body and (body:len()>512 and body:len() or body) or "nil")
end
end
-- http post提交表单数据功能演示
local function httpplus_app_post_form()
-- http post提交表单数据
-- http://httpbin.air32.cn/post为回环测试服务器,服务器收到post提交的表单数据后,还会下发同样的表单数据给设备
-- 如果请求成功,服务器应答的数据会保存到response.body中
local code, response = httpplus.request(
{
url = "http://httpbin.air32.cn/post",
forms = {username="LuatOS", password="123456"}
})
log.info("httpplus_app_post_form", code==200 and "success" or "error", code)
if code==200 then
log.info("httpplus_app_post_form headers", json.encode(response.headers or {}))
local body = response.body:query()
log.info("httpplus_app_post_form body", body and (body:len()>512 and body:len() or body) or "nil")
end
end
-- http post文件上传功能演示
local function httpplus_app_post_file()
-- hhtplus.request接口支持单文件上传、多文件上传、单文本上传、多文本上传、单/多文本+单/多文件上传
-- http://airtest.openluat.com:2900/uploadFileToStatic 仅支持单文件上传,并且上传的文件name必须使用"uploadFile"
-- 所以此处仅演示了单文件上传功能,并且"uploadFile"不能改成其他名字,否则会出现上传失败的应答
-- 如果你自己的http服务支持更多类型的文本/文件混合上传,可以打开注释自行验证
local code, response = httpplus.request(
{
url = "http://airtest.openluat.com:2900/uploadFileToStatic",
files =
{
["uploadFile"] = "/luadb/logo.jpg",
-- ["logo1.jpg"] = "/luadb/logo.jpg",
},
-- forms =
-- {
-- ["username"] = "LuatOS",
-- ["password"] = "123456",
-- },
})
log.info("httpplus_app_post_file", code==200 and "success" or "error", code)
if code==200 then
log.info("httpplus_app_post_file headers", json.encode(response.headers or {}))
local body = response.body:query()
log.info("httpplus_app_post_file body", body and (body:len()>512 and body:len() or body) or "nil")
end
end
-- http app task 的任务处理函数
local function httpplus_app_task_func()
while true do
-- 如果当前时间点设置的默认网卡还没有连接成功,一直在这里循环等待
while not socket.adapter(socket.dft()) do
log.warn("httpplus_app_task_func", "wait IP_READY", socket.dft())
-- 在此处阻塞等待默认网卡连接成功的消息"IP_READY"
-- 或者等待1秒超时退出阻塞等待状态;
-- 注意:此处的1000毫秒超时不要修改的更长;
-- 因为当使用exnetif.set_priority_order配置多个网卡连接外网的优先级时,会隐式的修改默认使用的网卡
-- 当exnetif.set_priority_order的调用时序和此处的socket.adapter(socket.dft())判断时序有可能不匹配
-- 此处的1秒,能够保证,即使时序不匹配,也能1秒钟退出阻塞状态,再去判断socket.adapter(socket.dft())
sys.waitUntil("IP_READY", 1000)
end
-- 检测到了IP_READY消息
log.info("httpplus_app_task_func", "recv IP_READY", socket.dft())
-- 普通的http get请求功能演示
httpplus_app_get()
-- http get下载压缩数据的功能演示
-- httpplus_app_get_gzip()
-- http post提交表单数据功能演示
httpplus_app_post_form()
-- -- http post提交json数据功能演示
-- httpplus_app_post_json()
-- http post提交纯文本数据功能演示
-- httpplus_app_post_text()
-- http post提交xml数据功能演示
-- httpplus_app_post_xml()
-- http post提交原始二进制数据功能演示
-- httpplus_app_post_binary()
-- http post文件上传功能演示
httpplus_app_post_file()
-- 60秒之后,循环测试
sys.wait(60000)
end
end
--创建并且启动一个task
--运行这个task的处理函数httpplus_app_task_func
sys.taskInit(httpplus_app_task_func)
五、产品支持说明
支持LuatOS开发的所有产品都支持httpplus扩展库。