1.11 HTTP 文件上傳的核心協議

?HTTP 文件上傳是 Web 開發中的常見需求,涉及到特殊的請求格式和處理機制。

一、HTTP 文件上傳的核心協議

1. 兩種主要方式
  • multipart/form-data(主流)
    支持二進制文件和表單字段混合傳輸,由?Content-Type?頭部標識。
  • application/x-www-form-urlencoded(傳統表單)
    僅支持文本數據,文件會被編碼為 Base64(體積增大 33%),已逐漸淘汰。
2. 關鍵請求頭
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Length: 12345
  • boundary:分隔符,用于標記不同表單字段的邊界。
  • Content-Length:請求體總長度(字節)。

3.請求體

請求體包含了實際要上傳的數據。對于文件上傳,數據被分割成多個部分,每部分由兩部分組成:一部分是頭部,描述了該部分的內容(如字段名和文件名),另一部分是實際的文件內容。每個部分都以--boundary開始,并以--boundary--結束

關鍵規則

  1. 字段頭部與內容之間必須有空行
    空行由?\r\n\r\n(CRLF CRLF)組成,是協議的硬性規定。

  2. 分隔符與字段頭部之間
    分隔符后可以緊跟字段頭部(無需空行),但實際請求中可能存在一個換行符(取決于客戶端實現)。

  3. 結束標記
    最后一個分隔符必須以?--?結尾(如?-----------------------------1234567890--)。

二、請求報文結構詳解

1. 基礎格式
POST /upload HTTP/1.1
Host: example.com
Content-Type: multipart/form-data; boundary=---------------------------1234567890-----------------------------1234567890
Content-Disposition: form-data; name="textField"Hello, World!
-----------------------------1234567890
Content-Disposition: form-data; name="file"; filename="example.txt"
Content-Type: text/plainThis is the file content.
-----------------------------1234567890--
2. 核心組成部分
  • 分隔符(Boundary)
    由?Content-Type?中的?boundary?指定,用于分隔不同字段。
  • 字段頭部(Headers)
    Content-Disposition: form-data; name="file"; filename="example.txt"
    Content-Type: text/plain
    
    ?
    • name:字段名(對應表單中的?name?屬性)。
    • filename:文件名(可選,僅文件字段需要)。
    • Content-Type:文件 MIME 類型(默認?application/octet-stream)。
  • 字段內容(Body)
    文件的二進制數據或文本值。

?完整示例

POST /upload HTTP/1.1
Host: example.com
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryABC123
Content-Length: 12345------WebKitFormBoundaryABC123
Content-Disposition: form-data; name="username"JohnDoe
------WebKitFormBoundaryABC123
Content-Disposition: form-data; name="file"; filename="test.txt"
Content-Type: text/plainHello, this is the content of test.txt.
------WebKitFormBoundaryABC123--

三、服務器處理流程

1. 解析步驟
  1. 讀取?Content-Type?中的?boundary
  2. 按分隔符分割請求體。
  3. 解析每個字段的頭部和內容。
2. Node.js 示例(原生實現.學習使用 該案例未做安全防護,未做文件分割,大文件會導致內存溢出.)
const http = require('http');
const fs = require('fs');
const path = require('path');const server = http.createServer((req, res) => {if (req.method === 'POST') {// 獲取 boundaryconst contentType = req.headers['content-type'];const boundary = `--${contentType.split('boundary=')[1]}`;const boundaryBuffer = Buffer.from(boundary);// 存儲完整請求體(二進制形式)let requestBuffer = Buffer.from('');// 收集所有數據塊(二進制形式)req.on('data', (chunk) => {requestBuffer = Buffer.concat([requestBuffer, chunk]);});req.on('end', () => {// 按 boundary 分割(使用二進制操作)const parts = splitBuffer(requestBuffer, boundaryBuffer);parts.forEach(part => {// 分離頭部和內容(二進制形式)const headerEnd = part.indexOf('\r\n\r\n');if (headerEnd === -1) return;const headersBuffer = part.slice(0, headerEnd);const contentBuffer = part.slice(headerEnd + 4); // +4 跳過 \r\n\r\n// 解析頭部(轉換為字符串)const headers = parseHeaders(headersBuffer.toString());// 如果是文件,保存到磁盤if (headers.filename) {// 移除內容末尾的 \r\n--const endIndex = contentBuffer.indexOf('\r\n--');const fileContent = endIndex !== -1 ? contentBuffer.slice(0, endIndex) : contentBuffer;// 生成安全的文件名(添加時間戳)const ext = path.extname(headers.filename);const safeFilename = `${Date.now()}_${Math.random().toString(36).substring(2, 10)}${ext}`;const savePath = path.join(__dirname, 'uploads', safeFilename);// 直接寫入二進制數據fs.writeFile(savePath, fileContent, (err) => {if (err) {console.error('保存文件失敗:', err);res.statusCode = 500;res.end('服務器錯誤');}});console.log(`文件已保存: ${savePath}`);}});res.end('上傳完成');});} else {//設置為utf-8編碼res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });res.end(`<form method="post" enctype="multipart/form-data"><input type="file" name="file"><button type="submit">上傳</button></form>`);}
});// 按 boundary 分割 Buffer
function splitBuffer(buffer, boundary) {const parts = [];let startIndex = 0;while (true) {const index = buffer.indexOf(boundary, startIndex);if (index === -1) break;if (startIndex > 0) {parts.push(buffer.slice(startIndex, index));}startIndex = index + boundary.length;// 檢查是否到達末尾if (buffer.slice(index + boundary.length, index + boundary.length + 2).toString() === '--') {break;}}return parts;
}// 解析頭部信息
function parseHeaders(headerText) {const headers = {};const lines = headerText.split('\r\n');lines.forEach(line => {if (!line) return;const [key, value] = line.split(': ');if (key === 'Content-Disposition') {const params = value.split('; ');params.forEach(param => {const [name, val] = param.split('=');if (val) headers[name] = val.replace(/"/g, '');});} else {headers[key] = value;}});return headers;
}// 創建上傳目錄
fs.mkdirSync(path.join(__dirname, 'uploads'), { recursive: true });server.listen(3000, () => {console.log('服務器運行在 http://localhost:3000');
});

四、?前端實現

  • 原生表單
    <form action="/upload" method="post" enctype="multipart/form-data"><input type="file" name="file"><input type="submit">
    </form>
    
  • AJAX 上傳(使用?FormData
    const formData = new FormData();
    formData.append('file', fileInput.files[0]);fetch('/upload', {method: 'POST',body: formData
    });
    

五 總結

  • 協議核心multipart/form-data?格式通過分隔符實現多字段傳輸。
  • 安全要點:該案例不適合生產使用. 生產使用建議使用第三方庫formidable?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/84650.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/84650.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/84650.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

安裝 Poppler(Windows)

下載 Poppler&#xff08;Windows&#xff09;&#xff1a;https://github.com/oschwartz10612/poppler-windows/releases/ 解壓在自己目錄下 配置系統環境變量&#xff1a;把 poppler-xx.x.x\bin 目錄加入你的環境變量 PATH 中。 檢查是否配置成功 pdfinfo

Java學習筆記之:初識nginx

Java學習筆記之&#xff1a;初識nginx PS&#xff1a;雖然總結的都很簡單&#xff0c;但是作為初學者并且本人記憶力較差所以每次學習新知識點后習慣性記錄下來&#xff0c;這樣加深一遍記憶并且便于日后復習。 介紹&#xff1a; Nginx是一款輕量級的Web服務器/反向代理服務器…

Middleware

中間件的定義&#xff1a;中間件是位于操作系統和應用程序之間的軟件層&#xff0c;用于解決分布式系統中通信、數據共享、資源管理等共性問題。消息隊列屬于通信中間件&#xff0c;用于在分布式系統中傳遞消息&#xff0c;實現應用解耦、異步通信和流量削峰。解耦系統&#xf…

Mac如何配置ZSH并使用Oh-my-zsh?讓你的終端更加實用、美觀

前言 現在&#xff0c;越來越多的人趨向使用ZSH取代(Linux)原本的Bash作為自己的終端Shell。的確&#xff0c;ZSH才是適用于現代的Shell&#xff1a; 更豐富的命令提示更鮮明的演示標記更強大的插件支持 什么是ZSH 回答什么是ZSH前&#xff0c;我們先解釋什么是Bash&#x…

C++11新標準

重點 auto 類型推導范圍 for 迭代初始化列表變參模板 新類型 C11新增了類型 long long 和 unsigned long long&#xff0c;以支持64位(或更寬)的整型;新增了類型 char16_t和 char32_t&#xff0c;以支持 16位和 32 位的字符表示;還新增了“原始”字符串。 常量 nullptr nu…

SpringAI Prompt提示詞

基本概念 Prompts提示詞 ? 提示詞的是引導AI模型輸出的輸入&#xff0c;提示詞的正確性直接影響模型輸出的。 Message消息 Message 接口封裝了 Prompt 文本內容、一組元數據屬性以及稱為 MessageType 的分類。Spring AI消息API&#xff1a; 其中最重要的就是角色&#xff1a; …

力扣刷題——二分查找

數組是存放在連續內存空間上的相同類型數據的集合數組下標都是從0開始的數組內存空間的地址是連續的正是因為數組在內存空間的地址是連續的&#xff0c;所以我們在刪除或者增添元素的時候&#xff0c;就難免要移動其他元素的地址。 使用二分查找法返回的元素下標可能不是唯一的…

黑群暉NAS部署DeepSeek模型與內網穿透實現本地AI服務

文章目錄 前言1.安裝Container Manager2. 啟動ssh功能3. ssh連接黑群暉4. 安裝Ollama5. 安裝deepseek模型6. 安裝open-webui圖形界面7. 安裝內網穿透7.1 下載cpolar套件7.2 配置群輝虛擬機7.3 配置公網地址小結 7.4 配置固定公網地址 總結 前言 在追求自建網絡存儲方案的極客群…

Rust 學習筆記:處理任意數量的 future

Rust 學習筆記&#xff1a;處理任意數量的 future Rust 學習筆記&#xff1a;處理任意數量的 future競爭的 future將控制權交給運行時構建我們自己的異步抽象 Rust 學習筆記&#xff1a;處理任意數量的 future 當兩個 future 切換到三個 future 時&#xff0c;我們也必須從使用…

2025年TCP洪水攻擊防護實戰全解析:從協議對抗到AI智能防御

一、2025年TCP洪水攻擊的新特征與挑戰 AI驅動的自適應攻擊 攻擊者利用生成式AI動態調整SYN報文特征&#xff08;如載荷內容、發送頻率&#xff09;&#xff0c;使攻擊流量與正常業務流量的差異率低至0.5%&#xff0c;傳統基于規則引擎的防御策略完全失效。 混合協議打擊常態化…

二、集成開發環境(IDE)

上節我們在終端演示了python虛擬環境的用法&#xff0c;但終端不方便代碼編寫和調試&#xff0c;本節介紹兩種常用的python集成開發環境&#xff1a;Pycharm和Jupter Notebook。Pycharm是最流行的Python IDE&#xff0c;下載網址&#xff1a;下載 PyCharm&#xff1a;JetBrains…

芯片電感需求趨勢及選型關鍵因素

隨著AI產業的快速發展&#xff0c;數據中心、AI芯片、服務器等算力基礎設施對于芯片電感等電子元件的要求不斷提升。另一方面&#xff0c;電子產品向高功率密度和小型化方向發展&#xff0c;電源模塊趨于小型化、低電壓、大電流&#xff0c;也對芯片電感提出了小型化、輕量化、…

Vue3+Element Plus表單驗證實戰:從零實現用戶管理

前言 在Vue3項目開發中&#xff0c;表單驗證是保證數據完整性和準確性的重要環節。Element Plus作為Vue3的流行UI組件庫&#xff0c;提供了強大的表單驗證功能。本文將基于一個用戶管理模塊的實戰案例&#xff0c;詳細介紹Vue3中如何使用Element Plus實現完整的表單驗證流程。…

力扣上C語言編程題:合并區間(涉及數組)

一. 簡介 本文記錄力扣網上涉及數組方面的編程題&#xff0c;主要以 C語言實現。 二. 力扣上C語言編程題&#xff1a;合并區間&#xff08;涉及數組&#xff09; 以數組 intervals 表示若干個區間的集合&#xff0c;其中單個區間為 intervals[i] [starti, endi] 。請你合并所…

SEO長尾詞與關鍵詞優化實戰

內容概要 在SEO優化體系中&#xff0c;核心關鍵詞與長尾詞的協同作用直接影響流量獲取效率與用戶觸達精度。本文將從基礎概念切入&#xff0c;系統梳理核心關鍵詞的篩選標準與競爭強度評估方法&#xff0c;并深入探討長尾詞在細分場景下的價值定位。通過分析用戶搜索行為與意圖…

博圖SCL語言教程:靈活加、減計數制作自己的增減計數器(CTUD)

博圖SCL語言教程&#xff1a;使用SCL實現增減計數器(CTUD) 一、什么是增減計數器(CTUD)&#xff1f; 增減計數器&#xff08;Up-Down Counter&#xff09;是PLC編程中的基礎功能塊&#xff0c;具有以下特性&#xff1a; CU (Count Up)&#xff1a;上升沿觸發計數值增加 CD (…

Android 應用被kill問題排查和處理

一、背景 博主有一款應用市場應用,同樣的應用,在Android 10上開啟三個下載正常,在Android 14上開啟下載安裝,很頻繁被kill。首先想到的是,是不是應用內存太高,導致被kill,通過工具分析內存也不高,后面就想到是不是系統本身分配給應用的內存就不高,后來通過排查,確實是和系統的…

從代碼學習深度強化學習 - 多臂老虎機 PyTorch版

文章目錄 前言創建多臂老虎機環境多臂老虎機算法基本框架(基類)1. ε-貪心算法 (Epsilon-Greedy)2. 隨時間衰減的ε-貪婪算法 (Decaying ε-Greedy)3. 上置信界算法 (Upper Confidence Bound, UCB)4. 湯普森采樣算法 (Thompson Sampling)總結前言 歡迎來到“從代碼學習深度強化…

Android學習之Window窗口

Android Window機制學習筆記 在使用Window Flag實現界面全屏功能時&#xff0c;發現自身對Android Window機制缺乏系統認知&#xff0c;因此進行了專項學習與整理。 本文主要參考以下優質資料&#xff1a; Android的Window詳解Android官方Window文檔 Window基本概念 1. Win…

華為云 Flexus+DeepSeek 征文|搭建部署Dify-LLM推理引擎,賦能AI Agent智能體實現動態聯網搜索能力

華為云 Flexus 云服務器 X 實例專門為 AI 應用場景設計。它提供了強大的計算能力&#xff0c;能夠滿足 DeepSeek 模型以及后續搭建 AI Agent 智能體過程中對于數據處理和模型運行的高要求。在網絡方面&#xff0c;具備高速穩定的網絡帶寬&#xff0c;這對于需要頻繁聯網搜索信息…