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
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/84464.shtml
英文地址,請注明出處:http://en.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 中一種強大的編程工具,核心作用是在不修改原函數代碼的前提下,為函數添加額外功能(如日志記錄、性能統計、權限校驗等)。它充分利用了 …