简介
本文是在 ESP32-CAN 中实现的,其他单片机实现方法一致,主要涉及 HTTP 发送文件。本章所采用的请求为 POST 请求 。GET 请求会更容易 。
分别讲解
HTTP请求报文头
?HTTP 请求报文格式如图:请求方法为 POST 或者 GET 。URL 为 请求地址,可以为 / 。协议版本 HTTP/1.1 即可。 回车符 \r 换行符\n 有几个必不可少的头部字段:
Host 服务器的域名/IP地址和端口号Content-Type 内容类型Content-Length 内容大小
HTTP 请求报文体
我们要发送文件,所以报文体当然就是文件了,当然,文件也有专门用来发送的格式 其中一种格式为:
–【随机码】【\r\n】 Content-Disposition: form-data; name=【数据标识】; filename=“【文件名】”【\r\n】 Content-Type: 【文件类型】【\r\n】 【文件二进制编码流】 –【随机码】–
文件类型如果是JPG的话就是image/jpeg
整合报文
Content-Type
随机码要在请求头 Content-Type 告诉服务器随机码是什么
Content-Type: multipart/form-data; boundary=【随机码】
Content-Length
Arduino 的 String 太长会出现BUG,所以我们还是用手动计算的方式来获取请求体的大小,而不是全部整合到一个字符串中再求字符串长度。
String fileHead = "--" + randomCode + "\r\n" +
"Content-Disposition: form-data; name=\"img\"; filename=\"" + randomCode + ".jpg\"" + "\r\n" +
"Content-Type: image/jpeg" + "\r\n";
size_t jpgsize = 0 ;
for( jpgsize = 0 ; ;jpgsize++ ){
if( fb->buf[jpgsize] == 0xff ){
if( fb->buf[jpgsize+1] ==0xd9 ){
jpgsize += 2 ;
break;
}
}
}
unsigned int bodySize = ( fileHead.length() + (jpgsize) + randomCode.length() + 4 + 2 );
Content-Length: 【bodySize请求体大小】
按顺序发送
做完这几步以后,就可以把我们的报文按顺序发送出去了,下面有一个 ESP32-CAN 发送一张图片并获取响应的例子。
ESP32-CAN实现图片上传代码段
void send_camera_img(){
WiFiClient client;
camera_fb_t *fb = esp_camera_fb_get();
string domain = "" ;
if ( client.connect(domain,80)){
Serial.println(" Success!");
} else{
Serial.println(" connection failed!");
client.stop();
return ;
}
if (!fb)
{
Serial.print("Camera capture failed");
}
else
{
String randomCode = "";
for( int i = 0 ; i < 10 ; i ++ ){
switch ( random(0,3) ){
case 0 :
randomCode += (char)random(48,58);
break;
case 1 :
randomCode += (char)random(65,91);
break;
case 2 :
randomCode += (char)random(97,123);
break;
}
}
String fileHead = "--" + randomCode + "\r\n" +
"Content-Disposition: form-data; name=\"img\"; filename=\"" + randomCode + ".jpg\"" + "\r\n" +
"Content-Type: image/jpeg" + "\r\n";
size_t jpgsize = 0 ;
for( jpgsize = 0 ; ;jpgsize++ ){
if( fb->buf[jpgsize] == 0xff ){
if( fb->buf[jpgsize+1] ==0xd9 ){
jpgsize += 2 ;
break;
}
}
}
client.println("POST / HTTP/1.1");
Serial.println("POST / HTTP/1.1");
client.println("Host: "+ domain);
Serial.println("Host: "+ domain);
client.println("Content-Type: multipart/form-data; boundary=" + randomCode );
Serial.println("Content-Type: multipart/form-data; boundary=" + randomCode );
client.println("Connection: close");
Serial.println("Connection: close");
client.println("Content-Length: " + String( fileHead.length() + (jpgsize) + randomCode.length() + 4 + 2 ) );
Serial.println("Content-Length: " + String( fileHead.length() + (jpgsize) + randomCode.length() + 4 + 2 ) );
client.println("");
Serial.println("");
client.println( fileHead );
Serial.println( fileHead );
for (size_t i = 0; i < jpgsize; i++)
{
client.write(fb->buf[i]);
}
client.println("");
client.print("--" + randomCode + "--");
Serial.println("--" + randomCode + "--");
esp_camera_fb_return(fb);
rubbishMeg = "";
while (client.connected() || client.available()){
if (client.available()){
char line = client.read();
rubbishMeg += line ;
Serial.print(line);
}
}
}
client.stop();
}
联系作者
E-mail: Mr_Xie_@outlook.com GitHub: https://github.com/MR-XieXuan 个人私站: https://main.mrxie.xyz/
?如果本文对您有帮助的话,可以给本文点一个赞👍或者是收藏本文📧。你的每一个赞可以给作者非常大的鼓励。 ?如果遇到困难,欢迎联系作者,你可以私聊作者或者添加作者QQ、发送电子邮件向作者寻求帮助。也可以在下方评论区向大家提问。你的问题如果在评论区被解决也可以给其他遇到同样问题的一个参考。 作者不易,期待你的关注?。
|