前端上傳文件有兩種方式
- 方式一:使用
FormData
發(fā)送 ajax 上傳
// 創(chuàng)建FormData對(duì)象
var formData = new FormData();
// 添加文件數(shù)據(jù)
var fileInput = document.querySelector('input[type="file"]');
formData.append('file', fileInput.files[0]);
// 創(chuàng)建XMLHttpRequest對(duì)象
var xhr = new XMLHttpRequest();
// 設(shè)置請(qǐng)求的配置信息
xhr.open('POST', 'api/upload', true);
xhr.send(formData);
// 監(jiān)聽(tīng)請(qǐng)求的完成事件
xhr.onload = function() {
if (xhr.status === 200) {
console.log('上傳成功!');
} else {
console.error('上傳失?。?);
}
};
- 方式二:使用 Form 表單上傳(需要指定
enctype="multipart/form-data
")
<form action="/api/upload" method="POST" enctype="multipart/form-data">
<p>
<input type="text" name="a" />
</p>
<p>
<input type="file" name="img" />
</p>
<p>
<button>提交</button>
</p>
</form>
文件上傳的兩種方式,他們有什么關(guān)系?
-
FormData
構(gòu)造函數(shù),用于創(chuàng)建FormData
實(shí)例。 - 允許通過(guò)
append()
方法向FormData
對(duì)象添加表單字段和文件數(shù)據(jù)。 - 自動(dòng)將表單字段和文件數(shù)據(jù)封裝成multipart/form-data格式的請(qǐng)求體,以便通過(guò)XMLHttpRequest或Fetch API發(fā)送。
- 在發(fā)送請(qǐng)求時(shí),會(huì)自動(dòng)將請(qǐng)求的Content-Type頭部設(shè)置為multipart/form-data。
multipart/form-data 是什么?
Multipart/form-data是一種在HTTP傳輸協(xié)議中用于在Web表單中傳輸文件的編碼方式。它是一種靈活的編碼方式,能夠同時(shí)處理表單中的多個(gè)字段和文件上傳。
在multipart/form-data編碼中,表單中的每個(gè)數(shù)據(jù)字段都被封裝成一個(gè)消息體,并以一定的分隔符分隔消息體。這個(gè)編碼方式使用了類(lèi)似于multipart/mixed的格式,但主要用于表單數(shù)據(jù)的傳輸。每個(gè)消息體包含一個(gè)字段名稱(chēng)和字段值,以及一個(gè)可選的文件上傳字段。
當(dāng)使用multipart/form-data編碼方式時(shí),表單數(shù)據(jù)被封裝成一條消息,每個(gè)控件對(duì)應(yīng)消息的一部分。這種編碼方式支持在提交表單時(shí)上傳文件,因此被廣泛應(yīng)用于文件上傳功能的實(shí)現(xiàn)中。
總結(jié)來(lái)說(shuō),multipart/form-data的編碼方式是一種將表單中的每個(gè)數(shù)據(jù)字段封裝成一個(gè)消息體的編碼方式,并以一定的分隔符分隔消息體。這種編碼方式支持在提交表單時(shí)上傳文件,并能夠處理多個(gè)字段和文件上傳。
multipart/form-data 實(shí)現(xiàn)原理
在form-data編碼中,表單數(shù)據(jù)被封裝成一條消息,以標(biāo)簽為單元,用分隔符分開(kāi)。這意味著表單數(shù)據(jù)被分割成多個(gè)部分,每個(gè)部分都以標(biāo)簽開(kāi)頭,以分隔符結(jié)尾。這樣可以同時(shí)上傳多個(gè)鍵值對(duì)或文件。
當(dāng)上傳文件時(shí),除了普通的鍵值對(duì)數(shù)據(jù)外,每個(gè)文件都會(huì)被封裝為一個(gè)獨(dú)立的消息部分。每個(gè)文件部分都包含一個(gè)Content-Type頭部,用于指定文件的媒體類(lèi)型(即文件類(lèi)型),以及一個(gè)Content-Disposition頭部,用于描述該文件部分的名稱(chēng)和是否應(yīng)該被顯示或保存。
由于有分隔符隔離每個(gè)部分,所以form-data既可以上傳鍵值對(duì),也可以上傳文件。同時(shí),由于它采用了鍵值對(duì)的方式,所以可以上傳多個(gè)文件或鍵值對(duì)。
POST / HTTP/1.1
Content-Length: 551
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="a"
1
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="img"; filename="截屏2024-01-17 10.13.02.png"
Content-Type: <Content-Type header here>
(data)
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="b"
2
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="file"; filename="截屏2024-01-17 16.40.30.png"
Content-Type: <Content-Type header here>
(data)
------WebKitFormBoundary7MA4YWxkTrZu0gW--
上傳文件為什么只能是 form-data 類(lèi)型的請(qǐng)求體?
HTTP請(qǐng)求體主要有以下幾種格式:
- multipart/form-data:主要用于表單數(shù)據(jù)的提交,特別是文件上傳。它會(huì)把表單數(shù)據(jù)封裝成一條消息,以標(biāo)簽為單位,用分隔符分開(kāi)。既可以上傳鍵值對(duì),也可以上傳文件。
- application/x-www-form-urlencoded:會(huì)將表單內(nèi)的數(shù)據(jù)轉(zhuǎn)換為鍵值對(duì),用&分隔。當(dāng)method為get時(shí),會(huì)將表單數(shù)據(jù)編碼為(name1=value1&name2=value2…),然后把這個(gè)字符串a(chǎn)ppend到url后面,用?分隔。這個(gè)格式不能提交文件,區(qū)別于multipart/form-data。
- raw:可以上傳任意格式的文本,包括text、json、xml、html等。
- binary:相當(dāng)于Content-Type:application/octet-stream,只可以上傳二進(jìn)制數(shù)據(jù),用來(lái)上傳文件。由于沒(méi)有鍵值,一次只能上傳一個(gè)文件。
由此可以看出 application/x-www-form-urlencoded 和 raw,只支持字符串,不支持二進(jìn)制文件。binary 和 multipart/form-data都支持二進(jìn)制文件,但 multipart/form-data可以以鍵值對(duì)的形式進(jìn)行文件上傳,試用起來(lái)更靈活。文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-805093.html
node 服務(wù)如何獲取到客戶(hù)端上傳的文件
我們可以借用 Express 官方維護(hù)的 multer 中間件文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-805093.html
const express = require("express");
const multer = require("multer");
const path = require("path");
const app = express();
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, path.resolve(__dirname, "./public/upload"));
},
filename: function (req, file, cb) {
// 時(shí)間戳-6位隨機(jī)字符.文件后綴
const timeStamp = Date.now();
const ramdomStr = Math.random().toString(36).slice(-6);
const ext = path.extname(file.originalname);
const filename = `${timeStamp}-${ramdomStr}${ext}`;
cb(null, filename);
},
});
const upload = multer({
storage,
limits: {
fileSize: 150 * 1024,
},
fileFilter(req, file, cb) {
//驗(yàn)證文件后綴名
const extname = path.extname(file.originalname);
const whitelist = [".jpg", ".gif", "png"];
if (whitelist.includes(extname)) {
cb(null, true);
} else {
cb(new Error(`your ext name of ${extname} is not support`));
}
},
});
app.post("/api/upload", upload.single("img"), (req, res) => {
const url = `/upload/${req.file.filename}`;
res.send({
code: 0,
msg: "",
data: url,
});
});
const port = 5008;
app.listen(port, () => {
console.log(`server listen on ${port}`);
});
到了這里,關(guān)于NodeJs 第十七章 文件上傳的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!