关于网络协议 HTTP 4 之POST

本文档介绍了HTTP的POST方法,主要用于客户端向服务器提交数据,如表单、文件上传和删除操作。通过构建一个支持POST方法的HTTP WebServer,实现了在网页上进行Lua控制台的远程调试。文章详细讲述了如何创建包含表单的HTML文件,以及WebServer的实现过程,包括接收POST数据、执行Lua命令并显示响应。特别指出,POST数据的长度不应超过1024字节,以避免问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前几节,HTTP服务器和客户端交流采用的都是GET方法。客户端向服务器请求一个文件,或者发送一个button附带的固定信息。

除了GET方法外,常用的还有
- POST 客户端向服务器发送信息,比如提交一个表单。
- PUT 向服务器上传文件
- DELETE 删除服务器上的文件。

这一节主要讲一下POST方法,代码采用HTTP 3介绍的WEB 框架。

我们做一个支持POST方法的HTTP WebServer,实现web下的lua控制台。

  • * 在手机和平板上,用浏览器远程调试nodemcu*

接上节

Step 7

我们首先写一个包含表单的HTML文件,form2.html,作为服务器的主页。

    <html>

      <head>
        <title> Remote Debug </title>
      </head>

      <body>
        <h1> Remote Debug Your Nodemcu</h1>
        <form  method="POST">
          <p>
            </br>
            Input your LUA command here:</br>
            <textarea name="comments" rows="2" cols="70"></textarea></br>

            </br>
            Submit your command</br>
            <input type="submit" /></br>

            </br>
            Response</br>
          </p>
        </form>

        <iframe name="content_frame"  width="500" height="100" src="print.txt" frameborder=0></iframe></br>

      </body>
    </html>
  • <html>,<head>,<body>标签已经讲过,我们来看<form>标签,代码算空行第9行
  • <form method="POST">定义了from的方法是POST,用于客户端向服务器提交数据。<form></form> 里有一个完整的的<p></p>
  • <p></p>里定义了两个对象:<texterea><input>

    • 13行,<texterea>定义一个输入文本框,名称为comments,POST提交后,文本框的输入内容...,会以comments=...的形式发送给服务器。

    rows定义了文本框的高度,两行。cols定义宽度。</br>代表空一行

    文本框长这样:

    • 17行,<input type="submit" />定义一个提交按钮,,用来提交form对象中所有输入的信息
  • <iframe>标签可以在html里插入视频,图像,html等文件。这里我们插入了一个txt文档print.txt, 方法为src = "print.txt",同时还定义了名称name,宽度width和高度height

    print.txt用来显示nodemcu执行后的响应信息

Step 8

有了主页,我们写一个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替换,没有就不替换。否则会把其它特殊字符替换后的结果覆盖掉。

  • 66行,替换后的comments交给nodemcu执行
  • 74-92行,发送文件,详情见http 3
  • 89-92行,如果文件名是print.txt, 发送一部分(1024byte)后,就重新初始化,
    • 这部分写得不好,最好是在文件发送完后再初始化。不过一般print.txt不会超过1024字符,通常没有问题

这段WebServer代码的思路

是在主页from2.html里嵌入一个txt文档print.txt,显示nodemcu的响应信息
- 当客户端post信息后。服务器就把代码发给nodemcu执行(nodemcu.input()),然后响应信息存到print.txt
- 同时,向客户端发送主页from2.html, 等到主页向客户端传送完,客户端向服务器请求get print.txt, 这时nodemcu已经执行完代码,print.txt已经存了响应信息。
- print.txt 被传送完后(1024byte),会被初始化。等待下一条命令。

要说明的问题

  • 文本框输入命令不要超过1024byte,否则可能出现问题。即便使用串口调试,命令行太长也有报错的可能。
  • 通过该界面可以上传文件,或者删除。可以用javascript 实现分行上传文件。ESPlore也是用分行上传的方式实现的。

Step 9

  • 把4个文件wf4.lua,from2.html,print.txt,favcion.ico上传,
    • 注意更新wf4.lua中的SSIDpassword
    • print.txt只要不是空文件就行,因为每次执行wf4.lua都会初始化。
    • favcion.ico是服务器的图表文件。
    • 这四个文件和这篇文档一起上传到贴论坛里了。
  • dofile('wf4.lua'),显示nodemcu的IP
  • 在浏览器的地址栏输入nodemcu的IP,不要使用360浏览器
  • 在文本框输入lua命令行,点击提交按钮,下方显示响应信息。
  • 界面如下图:
    这里写图片描述
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值