前几节,HTTP服务器和客户端交流采用的都是GET
方法。客户端向服务器请求一个文件,或者发送一个button附带的固定信息。
除了GET
方法外,常用的还有
- POST
客户端向服务器发送信息,比如提交一个表单。
- PUT
向服务器上传文件
- DELETE
删除服务器上的文件。
这一节主要讲一下POST方法,代码采用HTTP 3
介绍的WEB 框架。
接上节
我们首先写一个包含表单的HTML文件,form2.html
,作为服务器的主页。
Remote Debug
Remote Debug Your Nodemcu
,
,
标签已经讲过,我们来看
标签,代码算空行第9行
定义了from的方法是POST
,用于客户端向服务器提交数据。
里有一个完整的的
里定义了两个对象:
和
定义一个输入文本框,名称为comments
,POST提交后,文本框的输入内容...
,会以comments=...
的形式发送给服务器。rows
定义了文本框的高度,两行。cols
定义宽度。代表空一行
文本框长这样:
定义一个提交按钮,,用来提交form
对象中所有输入的信息标签可以在
html
里插入视频,图像,html等文件。这里我们插入了一个txt文档print.txt
, 方法为src = "print.txt"
,同时还定义了名称name
,宽度width
和高度height
print.txt
用来显示nodemcu执行后的响应信息
有了主页,我们写一个web server,名称为form2.lua
。内容上和上一节介绍的web server比较类似,只是传送文件部分用了网上最流行的写法,可靠性应该更高一些。
SSID = ""
password = ""
pin = 4
gpio.mode(pin, gpio.OUTPUT)
wifi.setmode(wifi.STATION)
wifi.sta.config(SSID,password)
wifi.sta.connect()
tmr.alarm(1, 1000, 1, function()
if wifi.sta.getip() == nil then
print("Connecting...")
else
tmr.stop(1)
print("Connected, IP is "..wifi.sta.getip())
end
end)
file.open("print.txt","w+")
file.write('Command:')
file.close()
srv=net.createServer(net.TCP,30)
srv:listen(80,function(conn)
-- save node.output to print.txt
function s_output(str)
if(conn~=nil) then
file.open("print.txt","a+")
file.write(str)
file.close()
end
end
node.output(s_output, 1)
conn:on("receive", function(conn,payload)
-- parse Header
local _, _, vars = string.find(payload, "[A-Z]+ /(.+) HTTP");
local _, _, method = string.find(payload, "([A-Z]+) /.* HTTP");
local filename = nil
if (method =="GET") then
if (vars == nil) then filename = "form2.html"
elseif (vars ~= nil) then filename = vars
end
elseif (method =="POST") then
local _, _, comments =
string.find(payload,"comments=(.*)")
local symbol = {
['%2B'] = '+',
['%2F'] = '/',
['%28'] = '(',
['%29'] = ')',
['%22'] = '"',
['%27'] = "'"
}
-- replace symbol in comments
if (comments ~= nil)then
for sym1,sym2 in pairs(symbol) do
com_sub,n = string.gsub(comments,'%'..sym1,sym2)
if n~=0 then comments = com_sub end
end
-- execute comments
print(comments)
node.input(comments)
end
-- redirect
filename = "form2.html"
end
-- send file
local pos = 0;
local function send ()
file.open(filename,"r")
if (file.seek("set",pos) == nil ) then
conn:close()
collectgarbage()
else
local buf2 = file.read(1024)
conn:send(buf2)
pos = pos +1024
end
file.close()
-- initialize print.txt
if (filename == "print.txt") then
file.open("print.txt","w+")
file.write('Command:')
file.close()
end
end
conn:on("sent", send)
send()
end )
end )
<*_>
很多代码和http 3
文档中的几乎一样,连接路由器的代码在前面的文档也可以找到。我们只介绍关键的代码:
- 代码算空行,第19到21行,file.open(),file.write(),file.close
打开print.txt
文件,初始化,然后关闭
- 26行,function s_output(str)
定义一个函数,把执行后的响应信息,存到print.txt
文档中
- 第27行,如果连接conn
不为空,即conn 没有close.
- 第28行,以追加方式a+
打开文件,字符写到文档末尾处
- 第29,30行,写字符串并关闭
- 37-47行,解析http head,详情见http 3
- 41行,对于get
方法
- 42行,如果刚连接,客户端没有请求文件,定位到主页form2.html
- 43行,如果客户端请求文件,就定位到要发送的文件
- 45行,如果是post
方法,46行 ,解析出commets
由于在html文本框输入的commets,遇到+
,/
,()
,""
会转换成%
开头的代码,所以要转换一下
- 49-50行,定义特殊符号转换表格
- 58-62行,for循环实现转换。
- 59行,对所有特殊字符循环个遍
- 60行,把特殊字符替换成本来的样子,如果恰巧commets没有该特殊字符,n=0
- 61行,如果comments里存在循环到的特殊字符,就把comments替换,没有就不替换。否则会把其它特殊字符替换后的结果覆盖掉。
http 3
print.txt
, 发送一部分(1024byte)后,就重新初始化, 是在主页from2.html
里嵌入一个txt文档print.txt
,显示nodemcu的响应信息
- 当客户端post信息后。服务器就把代码发给nodemcu执行(nodemcu.input()),然后响应信息存到print.txt
- 同时,向客户端发送主页from2.html
, 等到主页向客户端传送完,客户端向服务器请求get print.txt
, 这时nodemcu已经执行完代码,print.txt已经存了响应信息。
- print.txt 被传送完后(1024byte),会被初始化。等待下一条命令。