|
|
@@ -0,0 +1,314 @@
|
|
|
+
|
|
|
+-- LuaTools需要PROJECT和VERSION这两个信息
|
|
|
+PROJECT = "httpdemo"
|
|
|
+VERSION = "1.0.0"
|
|
|
+
|
|
|
+--[[
|
|
|
+本demo需要http库, 大部分能联网的设备都具有这个库
|
|
|
+http也是内置库, 无需require
|
|
|
+
|
|
|
+1. 如需上传大文件,请使用 httpplus 库, 对应demo/httpplus
|
|
|
+2.
|
|
|
+]]
|
|
|
+
|
|
|
+-- sys库是标配
|
|
|
+_G.sys = require("sys")
|
|
|
+--[[特别注意, 使用http库需要下列语句]]
|
|
|
+_G.sysplus = require("sysplus")
|
|
|
+
|
|
|
+
|
|
|
+-- Air780E的AT固件默认会为开机键防抖, 导致部分用户刷机很麻烦
|
|
|
+if rtos.bsp() == "EC618" and pm and pm.PWK_MODE then
|
|
|
+ pm.power(pm.PWK_MODE, false)
|
|
|
+end
|
|
|
+
|
|
|
+
|
|
|
+sys.taskInit(function()
|
|
|
+ -----------------------------
|
|
|
+ -- 统一联网函数, 可自行删减
|
|
|
+ ----------------------------
|
|
|
+ if wlan and wlan.connect then
|
|
|
+ -- wifi 联网, ESP32系列均支持
|
|
|
+ local ssid = "luatos1234"
|
|
|
+ local password = "12341234"
|
|
|
+ log.info("wifi", ssid, password)
|
|
|
+ -- TODO 改成esptouch配网
|
|
|
+ -- LED = gpio.setup(12, 0, gpio.PULLUP)
|
|
|
+ wlan.init()
|
|
|
+ wlan.setMode(wlan.STATION)
|
|
|
+ wlan.connect(ssid, password, 1)
|
|
|
+ local result, data = sys.waitUntil("IP_READY", 30000)
|
|
|
+ log.info("wlan", "IP_READY", result, data)
|
|
|
+ device_id = wlan.getMac()
|
|
|
+ elseif rtos.bsp() == "AIR105" then
|
|
|
+ -- w5500 以太网, 当前仅Air105支持
|
|
|
+ w5500.init(spi.HSPI_0, 24000000, pin.PC14, pin.PC01, pin.PC00)
|
|
|
+ w5500.config() --默认是DHCP模式
|
|
|
+ w5500.bind(socket.ETH0)
|
|
|
+ -- LED = gpio.setup(62, 0, gpio.PULLUP)
|
|
|
+ sys.wait(1000)
|
|
|
+ -- TODO 获取mac地址作为device_id
|
|
|
+ elseif mobile then
|
|
|
+ -- Air780E/Air600E系列
|
|
|
+ --mobile.simid(2)
|
|
|
+ -- LED = gpio.setup(27, 0, gpio.PULLUP)
|
|
|
+ device_id = mobile.imei()
|
|
|
+ log.info("ipv6", mobile.ipv6(true))
|
|
|
+ sys.waitUntil("IP_READY", 30000)
|
|
|
+ elseif http then
|
|
|
+ sys.waitUntil("IP_READY")
|
|
|
+ else
|
|
|
+ while 1 do
|
|
|
+ sys.wait(1000)
|
|
|
+ log.info("http", "当前固件未包含http库")
|
|
|
+ end
|
|
|
+ end
|
|
|
+ log.info("已联网")
|
|
|
+ sys.publish("net_ready")
|
|
|
+end)
|
|
|
+
|
|
|
+function demo_http_get()
|
|
|
+ -- 最普通的Http GET请求
|
|
|
+ local code, headers, body = http.request("GET", "https://www.air32.cn/").wait()
|
|
|
+ log.info("http.get", code, headers, body)
|
|
|
+ local code, headers, body = http.request("GET", "https://mirrors6.tuna.tsinghua.edu.cn/", nil, nil, {ipv6=true}).wait()
|
|
|
+ log.info("http.get", code, headers, body)
|
|
|
+ sys.wait(100)
|
|
|
+ local code, headers, body = http.request("GET", "https://www.luatos.com/").wait()
|
|
|
+ log.info("http.get", code, headers, body)
|
|
|
+
|
|
|
+ -- 按需打印
|
|
|
+ -- code 响应值, 若大于等于 100 为服务器响应, 小于的均为错误代码
|
|
|
+ -- headers是个table, 一般作为调试数据存在
|
|
|
+ -- body是字符串. 注意lua的字符串是带长度的byte[]/char*, 是可以包含不可见字符的
|
|
|
+ -- log.info("http", code, json.encode(headers or {}), #body > 512 and #body or body)
|
|
|
+end
|
|
|
+
|
|
|
+function demo_http_post_json()
|
|
|
+ -- POST request 演示
|
|
|
+ local req_headers = {}
|
|
|
+ req_headers["Content-Type"] = "application/json"
|
|
|
+ local body = json.encode({name="LuatOS"})
|
|
|
+ local code, headers, body = http.request("POST","http://site0.cn/api/httptest/simple/date",
|
|
|
+ req_headers,
|
|
|
+ body -- POST请求所需要的body, string, zbuff, file均可
|
|
|
+ ).wait()
|
|
|
+ log.info("http.post", code, headers, body)
|
|
|
+end
|
|
|
+
|
|
|
+function demo_http_post_form()
|
|
|
+ -- POST request 演示
|
|
|
+ local req_headers = {}
|
|
|
+ req_headers["Content-Type"] = "application/x-www-form-urlencoded"
|
|
|
+ local params = {
|
|
|
+ ABC = "123",
|
|
|
+ DEF = 345
|
|
|
+ }
|
|
|
+ local body = ""
|
|
|
+ for k, v in pairs(params) do
|
|
|
+ body = body .. tostring(k) .. "=" .. tostring(v):urlEncode() .. "&"
|
|
|
+ end
|
|
|
+ local code, headers, body = http.request("POST","http://echohttp.wendal.cn/post",
|
|
|
+ req_headers,
|
|
|
+ body -- POST请求所需要的body, string, zbuff, file均可
|
|
|
+ ).wait()
|
|
|
+ log.info("http.post.form", code, headers, body)
|
|
|
+end
|
|
|
+
|
|
|
+-- local function http_download_callback(content_len,body_len,userdata)
|
|
|
+-- print("http_download_callback",content_len,body_len,userdata)
|
|
|
+-- end
|
|
|
+
|
|
|
+-- local http_userdata = "123456789"
|
|
|
+
|
|
|
+function demo_http_download()
|
|
|
+
|
|
|
+ -- POST and download, task内的同步操作
|
|
|
+ local opts = {} -- 额外的配置项
|
|
|
+ opts["dst"] = "/data.bin" -- 下载路径,可选
|
|
|
+ opts["timeout"] = 30000 -- 超时时长,单位ms,可选
|
|
|
+ -- opts["adapter"] = socket.ETH0 -- 使用哪个网卡,可选
|
|
|
+ -- opts["callback"] = http_download_callback
|
|
|
+ -- opts["userdata"] = http_userdata
|
|
|
+
|
|
|
+ for k, v in pairs(opts) do
|
|
|
+ print("opts",k,v)
|
|
|
+ end
|
|
|
+
|
|
|
+ local code, headers, body = http.request("POST","http://site0.cn/api/httptest/simple/date",
|
|
|
+ {}, -- 请求所添加的 headers, 可以是nil
|
|
|
+ "",
|
|
|
+ opts
|
|
|
+ ).wait()
|
|
|
+ log.info("http.post", code, headers, body) -- 只返回code和headers
|
|
|
+
|
|
|
+ -- local f = io.open("/data.bin", "rb")
|
|
|
+ -- if f then
|
|
|
+ -- local data = f:read("*a")
|
|
|
+ -- log.info("fs", "data", data, data:toHex())
|
|
|
+ -- end
|
|
|
+
|
|
|
+ -- GET request, 开个task让它自行执行去吧, 不管执行结果了
|
|
|
+ sys.taskInit(http.request("GET","http://site0.cn/api/httptest/simple/time").wait)
|
|
|
+end
|
|
|
+
|
|
|
+function demo_http_post_file()
|
|
|
+ -- -- POST multipart/form-data模式 上传文件---手动拼接
|
|
|
+ local boundary = "----WebKitFormBoundary"..os.time()
|
|
|
+ local req_headers = {
|
|
|
+ ["Content-Type"] = "multipart/form-data; boundary="..boundary,
|
|
|
+ }
|
|
|
+ local body = "--"..boundary.."\r\n"..
|
|
|
+ "Content-Disposition: form-data; name=\"uploadFile\"; filename=\"luatos_uploadFile_TEST01.txt\""..
|
|
|
+ "\r\nContent-Type: text/plain\r\n\r\n"..
|
|
|
+ "1111http_测试一二三四654zacc\r\n"..
|
|
|
+ "--"..boundary
|
|
|
+
|
|
|
+ log.info("headers: ", "\r\n"..json.encode(req_headers))
|
|
|
+ log.info("body: ", "\r\n"..body)
|
|
|
+ local code, headers, body = http.request("POST","http://airtest.openluat.com:2900/uploadFileToStatic",
|
|
|
+ req_headers,
|
|
|
+ body -- POST请求所需要的body, string, zbuff, file均可
|
|
|
+ ).wait()
|
|
|
+ log.info("http.post", code, headers, body)
|
|
|
+
|
|
|
+ -- 也可用postMultipartFormData(url, params) 上传文件
|
|
|
+ postMultipartFormData(
|
|
|
+ "http://airtest.openluat.com:2900/uploadFileToStatic",
|
|
|
+ {
|
|
|
+ -- texts =
|
|
|
+ -- {
|
|
|
+ -- ["imei"] = "862991234567890",
|
|
|
+ -- ["time"] = "20180802180345"
|
|
|
+ -- },
|
|
|
+
|
|
|
+ files =
|
|
|
+ {
|
|
|
+ ["uploadFile"] = "/luadb/luatos_uploadFile.txt",
|
|
|
+ }
|
|
|
+ }
|
|
|
+ )
|
|
|
+end
|
|
|
+
|
|
|
+
|
|
|
+local function demo_http_get_gzip()
|
|
|
+ -- 这里用 和风天气 的API做演示
|
|
|
+ -- 这个API的响应, 总会gzip压缩过, 需要配合miniz库进行解压
|
|
|
+ local code, headers, body = http.request("GET", "https://devapi.qweather.com/v7/weather/now?location=101010100&key=0e8c72015e2b4a1dbff1688ad54053de").wait()
|
|
|
+ log.info("http.gzip", code)
|
|
|
+ if code == 200 then
|
|
|
+ local re = miniz.uncompress(body:sub(11), 0)
|
|
|
+ log.info("和风天气", re)
|
|
|
+ if re then
|
|
|
+ local jdata = json.decode(re)
|
|
|
+ log.info("jdata", jdata)
|
|
|
+ if jdata then
|
|
|
+ log.info("和风天气", jdata.code)
|
|
|
+ if jdata.now then
|
|
|
+ log.info("和风天气", "天气", jdata.now.text)
|
|
|
+ log.info("和风天气", "温度", jdata.now.temp)
|
|
|
+ end
|
|
|
+ end
|
|
|
+ end
|
|
|
+ end
|
|
|
+end
|
|
|
+
|
|
|
+sys.taskInit(function()
|
|
|
+ sys.wait(100)
|
|
|
+ -- 打印一下支持的加密套件, 通常来说, 固件已包含常见的99%的加密套件
|
|
|
+ -- if crypto.cipher_suites then
|
|
|
+ -- log.info("cipher", "suites", json.encode(crypto.cipher_suites()))
|
|
|
+ -- end
|
|
|
+
|
|
|
+ -------------------------------------
|
|
|
+ -------- HTTP 演示代码 --------------
|
|
|
+ -------------------------------------
|
|
|
+ sys.waitUntil("net_ready") -- 等联网
|
|
|
+
|
|
|
+ while 1 do
|
|
|
+ -- 演示GET请求
|
|
|
+ demo_http_get()
|
|
|
+ -- 表单提交
|
|
|
+ -- demo_http_post_form()
|
|
|
+ -- POST一个json字符串
|
|
|
+ -- demo_http_post_json()
|
|
|
+ -- 上传文件, mulitform形式
|
|
|
+ -- demo_http_post_file()
|
|
|
+ -- 文件下载
|
|
|
+ -- demo_http_download()
|
|
|
+ -- gzip压缩的响应, 以和风天气为例
|
|
|
+ -- demo_http_get_gzip()
|
|
|
+
|
|
|
+ sys.wait(1000)
|
|
|
+ -- 打印一下内存状态
|
|
|
+ log.info("sys", rtos.meminfo("sys"))
|
|
|
+ log.info("lua", rtos.meminfo("lua"))
|
|
|
+ sys.wait(600000)
|
|
|
+ end
|
|
|
+end)
|
|
|
+
|
|
|
+---- MultipartForm上传文件
|
|
|
+-- url string 请求URL地址
|
|
|
+-- req_headers table 请求头
|
|
|
+-- params table 需要传输的数据参数
|
|
|
+function postMultipartFormData(url, params)
|
|
|
+ local boundary = "----WebKitFormBoundary"..os.time()
|
|
|
+ local req_headers = {
|
|
|
+ ["Content-Type"] = "multipart/form-data; boundary="..boundary,
|
|
|
+ }
|
|
|
+ local body = {}
|
|
|
+
|
|
|
+ -- 解析拼接 body
|
|
|
+ for k,v in pairs(params) do
|
|
|
+ if k=="texts" then
|
|
|
+ local bodyText = ""
|
|
|
+ for kk,vv in pairs(v) do
|
|
|
+ print(kk,vv)
|
|
|
+ bodyText = bodyText.."--"..boundary.."\r\nContent-Disposition: form-data; name=\""..kk.."\"\r\n\r\n"..vv.."\r\n"
|
|
|
+ end
|
|
|
+ table.insert(body, bodyText)
|
|
|
+ elseif k=="files" then
|
|
|
+ local contentType =
|
|
|
+ {
|
|
|
+ txt = "text/plain", -- 文本
|
|
|
+ jpg = "image/jpeg", -- JPG 格式图片
|
|
|
+ jpeg = "image/jpeg", -- JPEG 格式图片
|
|
|
+ png = "image/png", -- PNG 格式图片
|
|
|
+ gif = "image/gif", -- GIF 格式图片
|
|
|
+ html = "image/html", -- HTML
|
|
|
+ json = "application/json" -- JSON
|
|
|
+ }
|
|
|
+
|
|
|
+ for kk,vv in pairs(v) do
|
|
|
+ if type(vv) == "table" then
|
|
|
+ for i=1, #vv do
|
|
|
+ print(kk,vv[i])
|
|
|
+ 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")
|
|
|
+ table.insert(body, io.readFile(vv[i]))
|
|
|
+ table.insert(body, "\r\n")
|
|
|
+ end
|
|
|
+ else
|
|
|
+ print(kk,vv)
|
|
|
+ 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")
|
|
|
+ table.insert(body, io.readFile(vv))
|
|
|
+ table.insert(body, "\r\n")
|
|
|
+ end
|
|
|
+ end
|
|
|
+ end
|
|
|
+ end
|
|
|
+ table.insert(body, "--"..boundary.."--\r\n")
|
|
|
+ body = table.concat(body)
|
|
|
+ log.info("headers: ", "\r\n" .. json.encode(req_headers), type(body))
|
|
|
+ log.info("body: " .. body:len() .. "\r\n" .. body)
|
|
|
+ local code, headers, body = http.request("POST",url,
|
|
|
+ req_headers,
|
|
|
+ body
|
|
|
+ ).wait()
|
|
|
+ log.info("http.post", code, headers, body)
|
|
|
+end
|
|
|
+
|
|
|
+
|
|
|
+-- 用户代码已结束---------------------------------------------
|
|
|
+-- 结尾总是这一句
|
|
|
+sys.run()
|
|
|
+-- sys.run()之后后面不要加任何语句!!!!!
|