http_app.lua 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512
  1. --[[
  2. @module http_app
  3. @summary http应用功能模块
  4. @version 1.0
  5. @date 2025.08.01
  6. @author 朱天华
  7. @usage
  8. 本文件为http应用功能模块,核心业务逻辑为:基于不同的应用场景,演示http核心库的使用方式;
  9. http核心库和httpplus扩展库的区别如下:
  10. | 区别项 | http核心库 | httpplus扩展库 |
  11. | --------------------------------- | ------------------------------------------------------------------------- | ---------------------------- |
  12. | 文件上传 | 文件最大64KB | 只要内存够用,文件大小不限 |
  13. | 文件下载 | 支持,只要文件系统空间够用,文件大小不限 | 不支持 |
  14. | http header的key: value的限制 | 所有header的value总长度不能超过4KB,单个header的value长度不能超过1KB | 只要内存够用,header长度不限 |
  15. | 鉴权URL自动识别 | 不支持 | 支持 |
  16. | 接收到的body数据存储支持zbuff | 不支持 | 支持,可以直接传输给uart等库 |
  17. | 接收到的body数据存储到内存中 | 最大支持32KB | 只要内存够用,大小不限 |
  18. | chunk编码 | 支持 | 不支持 |
  19. 本文件没有对外接口,直接在main.lua中require "http_app"就可以加载运行;
  20. ]]
  21. --[[
  22. 此处先详细解释下http.request接口的使用方法
  23. 接口定义:
  24. http.request(method, url, headers, body, opts, server_ca_cert, client_cert, client_key, client_password)
  25. 使用方法:
  26. local code, headers, body = http.request(method, url, headers, body, opts, server_ca_cert, client_cert, client_key, client_password).wait()
  27. 只能在task中使用
  28. 发送http请求到服务器,等待服务器的http应答,此处会阻塞当前task,等待整个过程成功结束或者出现错误异常结束或者超时结束
  29. 参数定义:
  30. method,stirng类型,必须包含此参数,表示HTTP请求方法,支持"GET"、"POST"、"HEAD"等所有HTTP请求方法
  31. url,string类型,必须包含此参数,表示HTTP请求URL地址,支持HTTP、HTTPS,支持域名、IP地址,支持自定义端口,标准的HTTP URL格式都支持
  32. headers,table或者nil类型,可选包含此参数,表示HTTP请求头,例如 {["Content-Type"] = "application/x-www-form-urlencoded", ["self_defined_key"] = "self_defined_value"}
  33. body,string或者zbuff或者nil类型,可选包含此参数,表示HTTP请求体,如果请求体是一个文件中的内容,要把文件内容读出来,赋值给body使用
  34. opts,table或者nil类型,可选包含此参数,表示HTTP请求的一些额外配置,包含以下内容
  35. {
  36. timeout -- -- number或者nil类型,单位毫秒,可选包含此参数,表示从发送请求到读取到服务器响应整个过程的超时时间,如果传入0,表示永久等待;如果没有传入此参数或者传入nil,则使用默认值10分钟
  37. dst -- 下载路径,string类型,当HTTP请求的数据需要保存到文件中时,此处填写完整的文件路径
  38. adapter -- 使用的网卡ID,number类型,例如4G网卡,SPI外挂以太网卡,WIFI网卡等;如果没有传入此参数,内核固件会自动选择当前时间点其他功能模块设置的默认网卡
  39. -- 除非你HTTP请求时,一定要使用某一种网卡,才设置此参数;如果没什么特别要求,不要使用此参数,使用系统中设置的默认网卡即可
  40. -- 这个参数和本demo中的netdrv_device.lua关系比较大,netdrv_device会设置默认网卡,此处http不要设置adapter参数,直接使用netdrv_device设置的默认网卡就行
  41. debug -- 调试开关,bool类型,true表示打开debug调试信息日志,false表示关闭debug调试信息日志,默认为关闭状态
  42. ipv6 -- 是否为ipv6,bool类型,true表示使用ipv6,false表示不使用ipv6,默认为false
  43. userdata -- 下载回调函数使用的用户自定义回调参数,做为callback回调函数的第三个参数使用
  44. callback -- 下载回调函数,function类型,当下载数据时,无论是保存到内存中,还是保存到文件系统中,如果设置了callback,内核固件中每收到一包body数据,都会自动执行一次callback回调函数
  45. -- 回调函数的调用形式为callback(content_len, body_len, userdata)
  46. -- content_len:number类型,数据总长度
  47. -- body_len:number类型,已经下载的数据长度
  48. -- userdata:下载回调函数使用的用户自定义回调参数
  49. }
  50. server_ca_cert,string类型,服务器ca证书数据,可选包含此参数,当客户端需要验证服务器证书时,需要此参数,如果证书数据在一个文件中,要把文件内容读出来,赋值给server_ca_cert
  51. client_cert,string类型,客户端证书数据,可选包含此参数,当服务器需要验证客户端证书时,需要此参数,如果证书数据在一个文件中,要把文件内容读出来,赋值给client_cert
  52. client_key, string类型,客户端加密后的私钥数据,可选包含此参数,当服务器需要验证客户端证书时,需要此参数,如果加密后的私钥数据在一个文件中,要把文件内容读出来,赋值给client_key
  53. client_password,string类型,客户端私钥口令数据,可选包含此参数,当服务器需要验证客户端证书时,需要此参数,如果私钥口令数据在一个文件中,要把文件内容读出来,赋值给client_password
  54. 返回值定义:
  55. http.request().wait()有三个返回值code,headers,body
  56. code表示执行结果,number类型,有以下两种含义:
  57. 1、code大于等于100时,表示服务器返回的HTTP状态码,例如200表示成功,详细说明可以通过搜索引擎搜索“HTTP状态码”自行了解
  58. 2、code小于0时,表示内核固件中检测到通信异常,有如下几种:
  59. -1 HTTP_ERROR_STATE 错误的状态, 一般是底层异常,请报issue
  60. -2 HTTP_ERROR_HEADER 错误的响应头部, 通常是服务器问题
  61. -3 HTTP_ERROR_BODY 错误的响应体,通常是服务器问题
  62. -4 HTTP_ERROR_CONNECT 连接服务器失败, 未联网,地址错误,域名错误
  63. -5 HTTP_ERROR_CLOSE 提前断开了连接, 网络或服务器问题
  64. -6 HTTP_ERROR_RX 接收数据报错, 网络问题
  65. -7 HTTP_ERROR_DOWNLOAD 下载文件过程报错, 网络问题或下载路径问题
  66. -8 HTTP_ERROR_TIMEOUT 超时, 包括连接超时,读取数据超时
  67. -9 HTTP_ERROR_FOTA fota功能报错,通常是更新包不合法
  68. headers有以下两种含义:
  69. 1、当code的返回值大于等于100时,headers表示服务器返回的应答头,table类型
  70. 2、当code的返回值小于0时,headers为nil
  71. body有以下三种含义
  72. 1、当code的返回值大于等于100时,如果请求的body数据不需要保存到文件中,而是直接保存到内存中,则body表示请求到的数据内容,string类型
  73. 2、当code的返回值大于等于100时,如果请求的body数据需要保存到文件中,则body表示保存请求数据后的文件的大小,number类型
  74. 3、当code的返回值小于0时,body为nil
  75. ]]
  76. -- http下载数据回调函数
  77. -- content_len:number类型,数据总长度
  78. -- body_len:number类型,已经下载的数据长度
  79. -- userdata:下载回调函数使用的用户自定义回调参数
  80. -- 每收到一包body数据,就会调用一次http_cbfunc回调函数
  81. local function http_cbfunc(content_len, body_len, userdata)
  82. log.info("http_cbfunc", content_len, body_len, userdata)
  83. end
  84. -- 普通的http get请求功能演示
  85. -- 请求的body数据保存到内存变量中,在内存够用的情况下,最大支持32KB的数据存储到内存中
  86. -- timeout可以设置超时时间
  87. -- callback可以设置回调函数,可用于实时检测body数据的下载进度
  88. local function http_app_get()
  89. -- https get请求https://www.air32.cn/网页内容
  90. -- 如果请求成功,请求的数据保存到body中
  91. local code, headers, body = http.request("GET", "https://www.air32.cn/").wait()
  92. log.info("http_app_get1",
  93. code==200 and "success" or "error",
  94. code,
  95. json.encode(headers or {}),
  96. body and (body:len()>512 and body:len() or body) or "nil")
  97. -- https get请求https://www.luatos.com/网页内容
  98. -- 请求超时时间为3秒,用户自己写代码时,不要照抄10秒,根据自己业务逻辑的需要设置合适的超时时间
  99. -- 回调函数为http_cbfunc,回调函数使用的第三个回调参数为"http_app_get2"
  100. -- 如果请求成功,请求的数据保存到body中
  101. code, headers, body = http.request("GET", "https://www.luatos.com/", nil, nil, {timeout=10000, userdata="http_app_get2", callback=http_cbfunc}).wait()
  102. log.info("http_app_get2",
  103. code==200 and "success" or "error",
  104. code,
  105. json.encode(headers or {}),
  106. body and (body:len()>512 and body:len() or body) or "nil")
  107. -- http get请求http://httpbin.air32.cn/get网页内容,超时时间为3秒
  108. -- 请求超时时间为3秒,用户自己写代码时,不要照抄3秒,根据自己业务逻辑的需要设置合适的超时时间
  109. -- 回调函数为http_cbfunc,回调函数使用的第三个回调参数为"http_app_get3"
  110. -- 如果请求成功,请求的数据保存到body中
  111. code, headers, body = http.request("GET", "http://httpbin.air32.cn/get", nil, nil, {timeout=3000, userdata="http_app_get3", callback=http_cbfunc}).wait()
  112. log.info("http_app_get3",
  113. code==200 and "success" or "error",
  114. code,
  115. json.encode(headers or {}),
  116. body and (body:len()>512 and body:len() or body) or "nil")
  117. end
  118. -- http get下载压缩数据的功能演示
  119. local function http_app_get_gzip()
  120. -- https get请求https://devapi.qweather.com/v7/weather/now?location=101010100&key=0e8c72015e2b4a1dbff1688ad54053de网页内容,超时时间为3秒
  121. -- 如果请求成功,请求的数据保存到body中
  122. local code, headers, body = http.request("GET", "https://devapi.qweather.com/v7/weather/now?location=101010100&key=0e8c72015e2b4a1dbff1688ad54053de").wait()
  123. log.info("http_app_get_gzip",
  124. code==200 and "success" or "error",
  125. code,
  126. json.encode(headers or {}),
  127. body and (body:len()>512 and body:len() or body) or "nil")
  128. -- 如果请求成功
  129. if code == 200 then
  130. -- 从body的第11个字节开始解压缩
  131. local uncompress_data = miniz.uncompress(body:sub(11,-1), 0)
  132. if not uncompress_data then
  133. log.error("http_app_get_gzip uncompress error")
  134. return
  135. end
  136. local json_data = json.decode(uncompress_data)
  137. if not json_data then
  138. log.error("http_app_get_gzip json.decode error")
  139. return
  140. end
  141. log.info("http_app_get_gzip json_data", json_data)
  142. log.info("http_app_get_gzip", "和风天气", json_data.code)
  143. if json_data.now then
  144. log.info("http_app_get_gzip", "和风天气", "天气", json_data.now.text)
  145. log.info("http_app_get_gzip", "和风天气", "温度", json_data.now.temp)
  146. end
  147. end
  148. end
  149. -- http get下载数据保存到文件中的功能演示
  150. -- 请求的body数据保存到文件中,在文件系统够用的情况下,文件大小不限
  151. -- timeout可以设置超时时间
  152. -- callback可以设置回调函数,可用于实时检测文件下载进度
  153. local function http_app_get_file()
  154. -- 创建/http_download目录,用来存放通过http下载的文件
  155. -- 重复创建目录会返回失败
  156. -- 在创建目录之前可以使用api判断下目录是否存在
  157. -- 不过只有最新版本的内核固件才支持判断目录是否存在的api
  158. -- 在编写本demo时还没有这个api
  159. -- 如果Luatools烧录软件时,没有勾选 清除FS分区,此处日志有可能输出error
  160. -- 如果输出error,不用理会,不会影响后续逻辑的执行
  161. -- 等后续的新版本内核固件支持 判断目录是否存在 的api之后,再加上api判断
  162. local download_dir = "/http_download/"
  163. local result, reason = io.mkdir(download_dir)
  164. if not result then
  165. log.error("http_app_get_file io.mkdir error", reason)
  166. end
  167. local file_path = download_dir.."get_file1.html"
  168. -- https get请求https://www.air32.cn/网页内容
  169. -- 如果请求成功,请求的数据保存到文件file_path中
  170. local code, headers, body_size = http.request("GET", "https://www.air32.cn/", nil, nil, {dst=file_path}).wait()
  171. log.info("http_app_get_file1",
  172. code==200 and "success" or "error",
  173. code,
  174. json.encode(headers or {}),
  175. body_size)
  176. -- 如果下载成功
  177. if code==200 then
  178. -- 读取文件大小
  179. local size = io.fileSize(file_path)
  180. log.info("http_app_get_file1", "io.fileSize="..size)
  181. if size~=body_size then
  182. log.error("io.fileSize doesn't equal with body_size, error", size, body_size)
  183. end
  184. --文件使用完之后,如果以后不再用到,根据需要可以自行删除
  185. os.remove(file_path)
  186. end
  187. file_path = download_dir.."get_file2.html"
  188. -- https get请求https://www.luatos.com/网页内容
  189. -- 请求超时时间为3秒,用户自己写代码时,不要照抄10秒,根据自己业务逻辑的需要设置合适的超时时间
  190. -- 回调函数为http_cbfunc,回调函数使用的第三个回调参数为"http_app_get_file2"
  191. -- 如果请求成功,请求的数据保存到文件file_path中
  192. code, headers, body_size = http.request("GET", "https://www.luatos.com/", nil, nil, {dst=file_path, timeout=10000, userdata="http_app_get_file2", callback=http_cbfunc}).wait()
  193. log.info("http_app_get_file2",
  194. code==200 and "success" or "error",
  195. code,
  196. json.encode(headers or {}),
  197. body_size)
  198. -- 如果下载成功
  199. if code==200 then
  200. -- 读取文件大小
  201. local size = io.fileSize(file_path)
  202. log.info("http_app_get_file2", "io.fileSize="..size)
  203. if size~=body_size then
  204. log.error("io.fileSize doesn't equal with body_size, error", size, body_size)
  205. end
  206. --文件使用完之后,如果以后不再用到,根据需要可以自行删除
  207. os.remove(file_path)
  208. end
  209. file_path = download_dir.."get_file3.html"
  210. -- http get请求http://httpbin.air32.cn/get网页内容,超时时间为3秒
  211. -- 请求超时时间为3秒,用户自己写代码时,不要照抄3秒,根据自己业务逻辑的需要设置合适的超时时间
  212. -- 回调函数为http_cbfunc,回调函数使用的第三个回调参数为"http_app_get_file3"
  213. -- 如果请求成功,请求的数据保存到文件file_path中
  214. code, headers, body_size = http.request("GET", "http://httpbin.air32.cn/get", nil, nil, {dst=file_path, timeout=3000, userdata="http_app_get_file3", callback=http_cbfunc}).wait()
  215. log.info("http_app_get_file3",
  216. code==200 and "success" or "error",
  217. code,
  218. json.encode(headers or {}),
  219. body_size)
  220. -- 如果下载成功
  221. if code==200 then
  222. -- 读取文件大小
  223. local size = io.fileSize(file_path)
  224. log.info("http_app_get_file3", "io.fileSize="..size)
  225. if size~=body_size then
  226. log.error("io.fileSize doesn't equal with body_size, error", size, body_size)
  227. end
  228. --文件使用完之后,如果以后不再用到,根据需要可以自行删除
  229. os.remove(file_path)
  230. end
  231. end
  232. -- http post提交表单数据功能演示
  233. local function http_app_post_form()
  234. local params = {
  235. username = "LuatOS",
  236. password = "123456"
  237. }
  238. local body = ""
  239. -- 拼接成url编码的键值对的形式
  240. for k, v in pairs(params) do
  241. body = body .. k .. "=" .. tostring(v):urlEncode() .. "&"
  242. end
  243. -- 删除最后一位的&字符,最终为string类型的username=LuatOS&password=123456
  244. body = body:sub(1,-2)
  245. -- http post提交表单数据
  246. -- http://httpbin.air32.cn/post为回环测试服务器,服务器收到post提交的表单数据后,还会下发同样的表单数据给设备
  247. -- ["Content-Type"] = "application/x-www-form-urlencoded" 表示post提交的body数据格式为url编码的键值对形式的表单数据
  248. -- 如果请求成功,服务器应答的数据会保存到resp_body中
  249. local code, headers, resp_body = http.request("POST", "http://httpbin.air32.cn/post", {["Content-Type"] = "application/x-www-form-urlencoded"}, body).wait()
  250. log.info("http_app_post_form",
  251. code==200 and "success" or "error",
  252. code,
  253. json.encode(headers or {}),
  254. resp_body and (resp_body:len()>512 and resp_body:len() or resp_body) or "nil")
  255. end
  256. -- http post提交json数据功能演示
  257. local function http_app_post_json()
  258. local params = {
  259. username = "LuatOS",
  260. password = "123456"
  261. }
  262. local body = json.encode(params)
  263. -- http post提交json数据
  264. -- http://httpbin.air32.cn/post为回环测试服务器,服务器收到post提交的json数据后,还会下发同样的json数据给设备
  265. -- ["Content-Type"] = "application/json" 表示post提交的body数据格式为json格式的数据
  266. -- 如果请求成功,服务器应答的数据会保存到resp_body中
  267. local code, headers, resp_body = http.request("POST", "http://httpbin.air32.cn/post", {["Content-Type"] = "application/json"}, body).wait()
  268. log.info("http_app_post_json",
  269. code==200 and "success" or "error",
  270. code,
  271. json.encode(headers or {}),
  272. resp_body and (resp_body:len()>512 and resp_body:len() or resp_body) or "nil")
  273. end
  274. -- http post提交纯文本数据功能演示
  275. local function http_app_post_text()
  276. -- http post提交纯文本数据
  277. -- http://httpbin.air32.cn/post为回环测试服务器,服务器收到post提交的纯文本数据后,还会下发同样的纯文本数据给设备
  278. -- ["Content-Type"] = "text/plain" 表示post提交的body数据格式为纯文本格式的数据
  279. -- 如果请求成功,服务器应答的数据会保存到resp_body中
  280. local code, headers, resp_body = http.request("POST", "http://httpbin.air32.cn/post", {["Content-Type"] = "text/plain"}, "This is a raw text message from LuatOS device").wait()
  281. log.info("http_app_post_text",
  282. code==200 and "success" or "error",
  283. code,
  284. json.encode(headers or {}),
  285. resp_body and (resp_body:len()>512 and resp_body:len() or resp_body) or "nil")
  286. end
  287. -- http post提交xml数据功能演示
  288. local function http_app_post_xml()
  289. -- [=[ 和 ]=] 之间是一个多行字符串
  290. local body = [=[
  291. <?xml version="1.0" encoding="UTF-8"?>
  292. <user>
  293. <name>LuatOS</name>
  294. <password>123456</password>
  295. </user>
  296. ]=]
  297. -- http post提交xml数据
  298. -- http://httpbin.air32.cn/post为回环测试服务器,服务器收到post提交的xml数据后,还会下发同样的xml数据给设备
  299. -- ["Content-Type"] = "text/xml" 表示post提交的body数据格式为xml格式的数据
  300. -- 如果请求成功,服务器应答的数据会保存到resp_body中
  301. local code, headers, resp_body = http.request("POST", "http://httpbin.air32.cn/post", {["Content-Type"] = "text/xml"}, body).wait()
  302. log.info("http_app_post_xml",
  303. code==200 and "success" or "error",
  304. code,
  305. json.encode(headers or {}),
  306. resp_body and (resp_body:len()>512 and resp_body:len() or resp_body) or "nil")
  307. end
  308. -- http post提交原始二进制数据功能演示
  309. local function http_app_post_binary()
  310. local body = io.readFile("/luadb/logo.jpg")
  311. -- http post提交原始二进制数据
  312. -- http://upload.air32.cn/api/upload/jpg为jpg图片上传测试服务器
  313. -- 此处将logo.jpg的原始二进制数据做为body上传到服务器
  314. -- 上传成功后,电脑上浏览器打开https://www.air32.cn/upload/data/jpg/,打开对应的测试日期目录,点击具体的测试时间照片,可以查看上传的照片
  315. -- ["Content-Type"] = "application/octet-stream" 表示post提交的body数据格式为原始二进制格式的数据
  316. -- 如果请求成功,服务器应答的数据会保存到resp_body中
  317. local code, headers, resp_body = http.request("POST", "http://upload.air32.cn/api/upload/jpg", {["Content-Type"] = "application/octet-stream"}, body).wait()
  318. log.info("http_app_post_binary",
  319. code==200 and "success" or "error",
  320. code,
  321. json.encode(headers or {}),
  322. resp_body and (resp_body:len()>512 and resp_body:len() or resp_body) or "nil")
  323. end
  324. local function post_multipart_form_data(url, params)
  325. local boundary = "----WebKitFormBoundary"..os.time()
  326. local req_headers = {
  327. ["Content-Type"] = "multipart/form-data; boundary="..boundary,
  328. }
  329. local body = {}
  330. -- 解析拼接 body
  331. for k,v in pairs(params) do
  332. if k=="texts" then
  333. local bodyText = ""
  334. for kk,vv in pairs(v) do
  335. print(kk,vv)
  336. bodyText = bodyText.."--"..boundary.."\r\nContent-Disposition: form-data; name=\""..kk.."\"\r\n\r\n"..vv.."\r\n"
  337. end
  338. table.insert(body, bodyText)
  339. elseif k=="files" then
  340. local contentType =
  341. {
  342. txt = "text/plain", -- 文本
  343. jpg = "image/jpeg", -- JPG 格式图片
  344. jpeg = "image/jpeg", -- JPEG 格式图片
  345. png = "image/png", -- PNG 格式图片
  346. gif = "image/gif", -- GIF 格式图片
  347. html = "image/html", -- HTML
  348. json = "application/json", -- JSON
  349. }
  350. for kk,vv in pairs(v) do
  351. if type(vv) == "table" then
  352. for i=1, #vv do
  353. print(kk,vv[i])
  354. table.insert(body, "--"..boundary.."\r\nContent-Disposition: form-data; name=\""..kk.."\"; filename=\""..vv[i]:match("[^%/]+%w$").."\"\r\nContent-Type: "..contentType[vv[i]:match("%.(%w+)$")].."\r\n\r\n")
  355. table.insert(body, io.readFile(vv[i]))
  356. table.insert(body, "\r\n")
  357. end
  358. else
  359. print(kk,vv)
  360. table.insert(body, "--"..boundary.."\r\nContent-Disposition: form-data; name=\""..kk.."\"; filename=\""..vv:match("[^%/]+%w$").."\"\r\nContent-Type: "..contentType[vv:match("%.(%w+)$")].."\r\n\r\n")
  361. table.insert(body, io.readFile(vv))
  362. table.insert(body, "\r\n")
  363. end
  364. end
  365. end
  366. end
  367. table.insert(body, "--"..boundary.."--\r\n")
  368. body = table.concat(body)
  369. log.info("headers: ", "\r\n" .. json.encode(req_headers), type(body))
  370. log.info("body: " .. body:len() .. "\r\n" .. body)
  371. local code, headers, resp_body = http.request("POST", url, req_headers, body).wait()
  372. log.info("post_multipart_form_data",
  373. code==200 and "success" or "error",
  374. code,
  375. json.encode(headers or {}),
  376. resp_body and (resp_body:len()>512 and resp_body:len() or resp_body) or "nil")
  377. end
  378. -- http post文件上传功能演示
  379. local function http_app_post_file()
  380. -- 此接口post_multipart_form_data支持单文件上传、多文件上传、单文本上传、多文本上传、单/多文本+单/多文件上传
  381. -- http://airtest.openluat.com:2900/uploadFileToStatic 仅支持单文件上传,并且上传的文件name必须使用"uploadFile"
  382. -- 所以此处仅演示了单文件上传功能,并且"uploadFile"不能改成其他名字,否则会出现上传失败的应答
  383. -- 如果你自己的http服务支持更多类型的文本/文件混合上传,可以打开注释自行验证
  384. post_multipart_form_data(
  385. "http://airtest.openluat.com:2900/uploadFileToStatic",
  386. {
  387. -- texts =
  388. -- {
  389. -- ["username"] = "LuatOS",
  390. -- ["password"] = "123456"
  391. -- },
  392. files =
  393. {
  394. ["uploadFile"] = "/luadb/logo.jpg",
  395. -- ["logo1.jpg"] = "/luadb/logo.jpg",
  396. }
  397. }
  398. )
  399. end
  400. -- http app task 的任务处理函数
  401. local function http_app_task_func()
  402. while true do
  403. -- 如果当前时间点设置的默认网卡还没有连接成功,一直在这里循环等待
  404. while not socket.adapter(socket.dft()) do
  405. log.warn("http_app_task_func", "wait IP_READY", socket.dft())
  406. -- 在此处阻塞等待默认网卡连接成功的消息"IP_READY"
  407. -- 或者等待1秒超时退出阻塞等待状态;
  408. -- 注意:此处的1000毫秒超时不要修改的更长;
  409. -- 因为当使用libnetif.set_priority_order配置多个网卡连接外网的优先级时,会隐式的修改默认使用的网卡
  410. -- 当libnetif.set_priority_order的调用时序和此处的socket.adapter(socket.dft())判断时序有可能不匹配
  411. -- 此处的1秒,能够保证,即使时序不匹配,也能1秒钟退出阻塞状态,再去判断socket.adapter(socket.dft())
  412. sys.waitUntil("IP_READY", 1000)
  413. end
  414. -- 检测到了IP_READY消息
  415. log.info("http_app_task_func", "recv IP_READY", socket.dft())
  416. -- 普通的http get请求功能演示
  417. http_app_get()
  418. -- http get下载压缩数据的功能演示
  419. http_app_get_gzip()
  420. -- http get下载数据保存到文件中的功能演示
  421. http_app_get_file()
  422. -- http post提交表单数据功能演示
  423. http_app_post_form()
  424. -- http post提交json数据功能演示
  425. http_app_post_json()
  426. -- http post提交纯文本数据功能演示
  427. http_app_post_text()
  428. -- http post提交xml数据功能演示
  429. http_app_post_xml()
  430. -- http post提交原始二进制数据功能演示
  431. http_app_post_binary()
  432. -- http post文件上传功能演示
  433. http_app_post_file()
  434. -- 60秒之后,循环测试
  435. sys.wait(60000)
  436. end
  437. end
  438. --创建并且启动一个task
  439. --运行这个task的处理函数http_app_task_func
  440. sys.taskInit(http_app_task_func)