最近一直在研究esp8266,对一个问题非常不解:怎样才能让前端(HTML)与后端(c++代码)进行数据通信。在网上找了很多示例代码,发现很多交换数据的方法都是在c语言中进行HTML语句的组合,再发送给客户端进行显示的:
void sendInfo() {
String str;
FSInfo fs_info;
LittleFS.info(fs_info);
str += "<h1>系统信息</h1>";
str += "<br>系统可用内存:" + (String)(ESP.getFreeHeap() / 1024) + "KB";
str += "<br>CPU频率:" + (String)ESP.getCpuFreqMHz() + "MHz";
str += "<br>LittleFS总容量:" + (String)(fs_info.totalBytes / 1024) + "KB";
str += "<br>LittleFS可用容量:" +
(String)((fs_info.totalBytes - fs_info.usedBytes) / 1024) + "KB";
str += "<br>已连接的客户端数量:" + (String)WiFi.softAPgetStationNum();
server.send(200, F("text/html"), str);
}
显而易见,这样的方法好处就是简单方便,适合少量数据的发送与显示。
但是,如果一次性需要发送大量数据,或者网页设计的很复杂,这种拼接数据的方法就不适用了。
那么有没有什么办法,既能在保证网页内容不被更改的情况下又能交换数据呢?
答案是:有!
html代码
如果曾经学习过html/js,那么看这句话就可以了:利用ajax
来交换数据!
如果没有学习过也没关系,马上去w3cschool
学习ajax
也是可以的!
不多说,直接贴代码:
<html>
<head>
<meta charset="utf-8" />
</head>
<script>
setInterval(() => {
getData();
}, 1000);
function getData() {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function () {
if (this.readyState == 4 && this.status == 200) {
console.log(this.responseText);
document.getElementById("data").innerHTML = this.responseText;
}
}
xhttp.open("GET", "/getData");
xhttp.send();
}
function sendData() {
console.log("button clicked");
var xhttp = new XMLHttpRequest();
xhttp.open("POST", "/sendData");
xhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xhttp.send("data="+document.getElementById("sometext").value);
}
</script>
<body>
<h1>WebInteractiveTest</h1>
<p id="data">Loading...</p>
<br />
<input id="sometext" type='text' name='PASSWORD' placeholder=''>
</body>
<button onclick="sendData()">SendData</button>
</html>
Arduino代码
#include <ESP8266WebServer.h>
ESP8266WebServer server(80);
const char* webpage PROGMEM =
"<meta charset=utf-8><meta name=\'viewport\' "
"content=\'width=device-width,initial-scale=1\'><script>function "
"getData(){var e=new "
"XMLHttpRequest;e.onreadystatechange=function(){4==this.readyState&&200=="
"this.status&&(console.log(this.responseText),document.getElementById("
"\"data\").innerHTML=this.responseText)},e.open(\"GET\",\"/"
"getData\"),e.send()}function sendData(){console.log(\"button "
"clicked\");var e=new "
"XMLHttpRequest;e.open(\"POST\",\"/"
"sendData\"),e.setRequestHeader(\"Content-type\",\"application/"
"x-www-form-urlencoded\"),e.send(\"data=\"+document.getElementById("
"\"sometext\").value)}setInterval(()=>{getData()},1e3)</"
"script><h1>WebInteractiveTest</h1><p id=data>Loading...</p><br><input "
"id=sometext name=PASSWORD placeholder=\"\"><button "
"οnclick=sendData()>SendData</button>";
void handleIndex() {
server.send(200, F("text/html"), webpage); }
void getData() {
Serial.printf("Raw Arguments:%s\n", server.arg(F("plain")).c_str());
server.send(200);
}
void sendData() {
static int data;
server.send(200, F("text/plain"), (String)data);
data++;
}
void setup() {
Serial.begin(115200);
WiFi.mode(WIFI_AP);
WiFi.softAP(F("ESP_TEST"));//热点:ESP_TEST,无密码
server.on("/", handleIndex);
server.on(F("/getData"), sendData);
server.on(F("/sendData"), getData);
server.begin();
}
void loop() {
server.handleClient(); }
代码解析
(其实是很简单的代码,但是以防万一以后自己看不懂了,还是做个注释比较好)
html部分,js每隔一秒向/getData
请求一个数据,并将数据打印到控制台上,且将<id="data">
的标签中的内容改为接受到的数据。
c++部分,自增data
变量且发送
发送数据则采用POST
方法,ajax post
数据到/sendData
处,c++部分接受并打印到串口。