http协议同时传输文本和数据的新理解

首先,承认本人对于http协议认知确实不够,从来没有仔细研究这一块。

其次,这回确实要把自己十几年的理解更新一下了,主要还是自己过去没有认真研究过http协议。

这一次是这么回事,碰到一个情况,要在一次消息中传输文本和照片,这个按说很常见,过去写网页都是表单中就直接用了,也没有碰到过自己封装协议的情况。

这回呢,因为客户端是单片机,单片机这块之前也是单独提交要么文本,要么图片,没有一次性传过多种数据。

然后呢,我让kimi给我代码,结果给我的是流指针的方式

kimi错误方案一:

// 获取底层 WiFiClient 对象WiFiClient *stream = http.getStreamPtr();if (stream) {// 发送文本部分stream->print(body);// 发送图片数据stream->write(current_fb->buf, current_fb->len);// 发送结束边界stream->print(endBoundary);

WiFiClient 流指针在esp32单片机实测,压根没法正确初始化,至于原因,就不想找了,怎么测都是不行的,初始化后都是false。既然库中有这个功能,按说是能用的,也可能是我单片机中性芯片的问题。

下来事情呢,我就想自己拼接字符串给服务器。

kimi又给我错误方案二:

// 构建请求体String body;body += "--" + boundary + "\r\n";body += "Content-Disposition: form-data; name=\"message\"\r\n\r\n";body += photo_text + "\r\n";body += "--" + boundary + "\r\n";body += "Content-Disposition: form-data; name=\"image\"; filename=\"photo.jpg\"\r\n";body += "Content-Type: image/jpeg\r\n\r\n";String endBoundary = "\r\n--" + boundary + "--\r\n";// 计算总请求体长度size_t totalLen = body.length() + current_fb->len + endBoundary.length();// 设置请求体长度http.addHeader("Content-Length", String(totalLen));// 构建完整的请求体String fullBody = body;fullBody += String((char*)current_fb->buf, current_fb->len); // 直接将图片的二进制数据追加到字符串中

因为  fullBody += String((char*)current_fb->buf, current_fb->len); 其实实际加入协议的是字符串化的二进制,php服务器端 $_FILES['image'];读取的是二进制,所以肯定对不上,就会报错误3.

这个事情说明,不要完全依赖于AI,他会反复给一个错误的方向,你怎么都调不通,最终没有办法,只好自己亲自下场把内容研究透彻。

经过我和kimi的唇枪舌战,kimi终于开窍了,给我了第三个方案。【这里我要骂AI了】

// 发送HTTP POST请求Serial.println("Sending HTTP POST request");HTTPClient http;http.begin(serverURL);String boundary = "----ESP32_CAMERA_BOUNDARY";http.addHeader("Content-Type", "multipart/form-data; boundary=" + boundary);http.addHeader("User-Agent", "ESP32-Camera");http.setTimeout(60000);// 构建请求体的文本部分String body;body += "--" + boundary + "\r\n";body += "Content-Disposition: form-data; name=\"message\"\r\n\r\n";body += photo_text + "\r\n";body += "--" + boundary + "\r\n";body += "Content-Disposition: form-data; name=\"image\"; filename=\"photo.jpg\"\r\n";body += "Content-Type: image/jpeg\r\n\r\n";String endBoundary = "\r\n--" + boundary + "--\r\n";// 计算总请求体长度size_t totalLen = body.length() + current_fb->len + endBoundary.length();// 设置请求体长度http.addHeader("Content-Length", String(totalLen));// 构建完整的请求体http.addHeader("Content-Type", "multipart/form-data; boundary=" + boundary);// 发送请求http.begin(serverURL);int httpCode = http.sendRequest("POST", body.c_str(), body.length());if (httpCode == 200) {// 文本部分发送成功,现在发送图片数据http.write(current_fb->buf, current_fb->len);http.write(endBoundary.c_str(), endBoundary.length());Serial.println("Image uploaded successfully");} else {Serial.println("Failed to send text part of the request");}http.end();Serial.println("arduino HTTP request completed");

这是一个通过两次发送数据,达到目的的一个方案,这个我是可以接受的,毕竟在同一个函数任务中,但是这么一个方案明明很简单为啥AI给我搞了两天,我和他激辩很久,才告诉我。。。好吧,果然人还是要靠自己。

其实吧,这个事情还有很多解决方案,比如base64,这是经常用的,再比如使用ArduinoHttpClient库,只是这次就想死磕多类型数据协议封装,才搞了好几天。

=============================

说一下最终决定写本文的目的吧。之所以被AI的这几套方案套了三天了,根源在于自己对于http的理解有问题。也是因为没有完全了解它。

现在更正一下我的认知,我一直以为http就是一去一回的,就是送过去,返回结果。

因为用惯了api什么的,写惯了网页,之前都是这么用的,最惭愧的是以前给小弟也是这么讲的(此处脸部温度180度)。尽管我很早,在20年前就知道长连接这个事情,但是默认的访问我一直认知上认为是一去一回,然后通讯中断。

直到今天(再次脸红),我和AI沟通了原因,http1.0的协议确实默认不支持长连接,都是一去一回就完事了。本人最早用http差不多在2003年,而http1.1是1997年就出来了,所以最早的对浏览器的认知确实是有问题的,十几年来一直认为默认就是一去一回,而现在的协议肯定都是http1.1的,问了ai默认都是http1.1,也就是早就支持默认长连接,断开的话需要代码控制断开。

这次去底层拼接,才搞明白这个事,真的是愚钝了。(脸红+1)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/bicheng/84464.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

《安富莱嵌入式周报》第354期: 开源36通道16bit同步数据采集卡,开源PoE以太网GPIB,分体式键盘DIY,微软WSL开源,USB转车载以太网

周报汇总地址:嵌入式周报 - uCOS & uCGUI & emWin & embOS & TouchGFX & ThreadX - 硬汉嵌入式论坛 - Powered by Discuz! 视频版: https://www.bilibili.com/video/BV1kJThzxETY/ 《安富莱嵌入式周报》第354期: 开源36通道16bit同…

Hyperlane 框架详解与使用指南

hyperlane 是一个高性能且轻量级的 Rust HTTP 框架,设计目标是简化现代 Web 服务的开发,同时兼顾灵活性和性能表现。本文将详细介绍 hyperlane 框架的核心功能、API 设计、生命周期模型、路由支持及性能测试结果,帮助开发者快速掌握和应用该框…

JavaScript 中的 ES|QL:利用 Apache Arrow 工具

作者:来自 Elastic Jeffrey Rengifo 学习如何将 ES|QL 与 JavaScript 的 Apache Arrow 客户端工具一起使用。 想获得 Elastic 认证吗?了解下一期 Elasticsearch Engineer 培训的时间吧! Elasticsearch 拥有众多新功能,助你为自己…

从零实现富文本编辑器#5-编辑器选区模型的状态结构表达

先前我们总结了浏览器选区模型的交互策略,并且实现了基本的选区操作,还调研了自绘选区的实现。那么相对的,我们还需要设计编辑器的选区表达,也可以称为模型选区。编辑器中应用变更时的操作范围,就是以模型选区为基准来…

一个小小的 flask app, 几个小工具,拼凑一下

1. 起因, 目的: 自己的工具,为自己服务。给大家做参考。项目地址: https://github.com/buxuele/flask_utils 2. 先看效果 3. 过程: 一个有趣的 Flask 工具集:从无到有的开发历程 缘起:为什么要做这个项目&#xff…

织梦dedecms怎样用标签调用随机数?

​在使用织梦模板建站中,随机数作为一个偶尔使用到的参数,在具体使用中虽然用的少,但是今天跟版网小编给大家介绍下,大家可以参考下: 实现随机数的调用可以使用下面的js: 方法一:js代码 Math…

访问服务器项目,服务器可以ping通,但是端口访问不到

原因:端口未开放 假设项目部署服务器为205,在90服务器访问205项目 1、首先在205确定项目启动,看端口是否占用 # Windows(检查端口占用) netstat -ano | findstr "8103"期望输出: TCP 0.0.…

云原生核心技术 (7/12): K8s 核心概念白话解读(上):Pod 和 Deployment 究竟是什么?

大家好,欢迎来到《云原生核心技术》系列的第七篇! 在上一篇,我们成功地使用 Minikube 或 kind 在自己的电脑上搭建起了一个迷你但功能完备的 Kubernetes 集群。现在,我们就像一个拥有了一块崭新数字土地的农场主,是时…

华为云Flexus+DeepSeek征文 | 基于ModelArts Studio、DeepSeek大模型和Dify搭建网站智能客服助手

目录 一、前言 二、ModelArts Studio(MaaS)介绍与应用场景 2.1ModelArts Studio(MaaS)介绍 2.2 ModelArts Studio(MaaS)使用场景 2.3 开通MaaS服务 2.4 开通DeepSeek-V3商用服务 三、华为云Flexus简介 3.1 …

『uniapp』url拦截屏蔽 避免webview中打开淘宝店铺自动跳转淘宝

目录 分析1. wv.overrideUrlLoading2. 参数 `mode: allow`3. 参数 `match: ^(http|https)://.*`4. 回调函数 `function(e) { console.warn(allow url:, e.url); }`作用:可能的应用场景:核心代码总结欢迎关注 『uniapp』 专栏,持续更新中 欢迎关注 『uniapp』 专栏,持续更新…

将对透视变换后的图像使用Otsu进行阈值化,来分离黑色和白色像素。这句话中的Otsu是什么意思?

Otsu 是一种自动阈值化方法,用于将图像分割为前景和背景。它通过最小化图像的类内方差或等价地最大化类间方差来选择最佳阈值。这种方法特别适用于图像的二值化处理,能够自动确定一个阈值,将图像中的像素分为黑色和白色两类。 Otsu 方法的原…

Zookeeper 和 Kafka 版本与 JDK 要求

Apache Zookeeper 和 Apache Kafka 在不同版本中对 JDK 的要求如下表所示(基于官方文档和历史版本记录整理): 1. Zookeeper 版本与 JDK 要求 Zookeeper 版本要求的最低 JDK 版本说明3.4.x 系列JDK 6生产环境建议用 JDK 8(旧版兼容性强)。3.5.x 系列(3.5.5+)JDK 83.5.0 …

V837s-SDK Telnetd服务连接不上异常解决

目录 前言 一、检查 Telnetd 服务是否启动 二、问题解决 总结 前言 在基于 V837s-SDK 进行开发的过程中,Telnetd 服务连接不上是一个较为常见且棘手的问题。Telnet 作为一种远程登录协议,在开发调试时为我们提供了便捷的远程操作方式。若其连接出现异常,将严重影响开发进度…

滑动窗口最大值和最小值

题目: 思路: 窗口进行滑动时,需要快速获取min和max,因此需要一个结构来保存最值,而不是临时计算。动态的最值更新容易联想到单调栈,但是这里需要频繁增删元素,因此用双端队列,front…

JVM——对象创建全家桶:JVM中对象创建的模式及最佳实践

引入 在 Java 应用开发中,对象创建是最基础且高频的操作,但往往也是性能优化的关键切入点。想象一个在线阅读平台,每天需要创建数百万个 Book 对象来统计阅读数据。如果每个对象的创建过程存在内存浪费或性能瓶颈,累积效应将导致…

VSCode中PHP使用Xdebug

本地环境 windows10php8.2 ntsxdebug v3thinkphp v8 下载Xdebug Xdebug下载地址 从xdebug下载地址,下载最新的xdebug,解压后将php_xdebug.dll放入php目录的ext目录下 配置php.ini [Xdebug] zend_extension php_xdebug xdebug.client_host 127.0.0.1 xdebug.client_port…

金融系统渗透测试

金融系统渗透测试是保障金融机构网络安全的核心环节,它的核心目标是通过模拟攻击手段主动发现系统漏洞,防范数据泄露、资金盗取等重大风险。 一、金融系统渗透测试的核心框架 合规性驱动 需严格遵循《网络安全法》《数据安全法》及金融行业监管要求&am…

高考志愿填报管理系统---开发介绍

高考志愿填报管理系统是一款专为教育机构、学校和教师设计的学生信息管理和志愿填报辅助平台。系统基于Django框架开发,采用现代化的Web技术,为教育工作者提供高效、安全、便捷的学生管理解决方案。 ## 📋 系统概述 ### 🎯 系统定…

PHP 项目中新增定时任务类型的详细步骤(以 CRMEB 为例)

1.首先需要在下面文件中增加定时任务类型 2.在app\services\system\crontab\CrontabRunServices类中增加第一步中与定时任务类型同名的方法,注意需要下划线转小驼峰 例如定时任务的类型为:order_tick,而在CrontabRunServices类中的方法名称为&#xff1…

Day27 函数专题2:装饰器

1.装饰器的思想:进一步复用 装饰器(Decorator)是 Python 中一种强大的编程工具,核心作用是在不修改原函数代码的前提下,为函数添加额外功能(如日志记录、性能统计、权限校验等)。它充分利用了 …