1. 技術棧前端/后端 原生JS test
2.代碼部分
2.1 前端
2.1.1 Form表單提交方式 文件名: upload.form.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta http-equiv="X-UA-Compatible" content="ie=edge" /> <title>upload by form</title> </head> <body> <form action="/upload" enctype="multipart/form-data" method="post"> <input type="file" name="avatar" id="avatar" multiple="multiple" /> <input type="submit" value="form上傳頭像" id="submit" /> </form> <img id="img" /> </body> <script> window.onload = () => { const avatar = document.getElementById("avatar"); const img = document.getElementById("img"); avatar.onchange = e => { const file = e.target.files[0]; //創建讀取文件的對象 const reader = new FileReader(); //使用該對象讀取file文件 reader.readAsDataURL(file); //讀取文件成功后執行的方法函數 reader.onload = function(e) { //讀取成功后返回的一個參數e,整個的一個進度事件 //選擇所要顯示圖片的img,要賦值給img的src就是e中target下result里面 //的base64編碼格式的地址 img.src = e.target.result; }; }; }; </script> </html>
2.1.2 Ajax異步提交方式 文件名: upload.ajax.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta http-equiv="X-UA-Compatible" content="ie=edge" /> <title>upload by Ajax</title> </head> <body> <input type="file" id="avatar" multiple="multiple" /> <button type="button" id="submit">ajax上傳頭像</button> <img src="" id="img" /> </body> <script> window.onload = () => { const btn = document.getElementById("submit"); const img = document.getElementById("img"); const avatar = document.getElementById("avatar"); avatar.onchange = e => { const file = e.target.files[0]; const reader = new FileReader(); reader.readAsDataURL(file); reader.onload = e => { img.src = e.target.result; }; }; submit.onclick = () => { if(!avatar.files[0]) { alert('選擇圖片!') return false } const formData = new FormData(); formData.append("avatar", avatar.files[0]); const xhr = new XMLHttpRequest(); xhr.onreadystatechange = () => { if (xhr.readyState === 4 && xhr.status === 200) { console.log(xhr.responseText) } }; // 上傳進度 xhr.upload.addEventListener( "progress", e => { if (e.lengthComputable) { console.log("percent: ", (e.loaded / e.total) * 100 + "%"); } }, false ); // 上傳路徑這里寫成相對路徑 避免環境變化 xhr.open("POST", "./upload"); xhr.send(formData); }; }; </script> </html>
2.2 后端部分 文件名: upload.2.js
const http = require("http");
const fs = require("fs");
const formidable = require("formidable");
const pathFn = require("path");
http
.createServer((req, res) => {
if (req.url === "/upload" && req.method === "POST") {
const form = new formidable.IncomingForm();
const savePath = pathFn.join(__dirname, "/upload");
// 檢查文件加是否已經存在 這里用同步方法
if (!fs.existsSync(savePath)) {
fs.mkdirSync(savePath);
}
form.uploadDir = savePath;
form.parse(req, (err, fields, files) => {
res.writeHead(200, { "Content-Type": "text/plain" });
// 取文件路徑 和 文件名字
const { path, name } = files.avatar;
// 重命名
fs.rename(path, pathFn.join(savePath, "/", name), err => {
if (err) {
res.writeHead(200, { "Content-Type": "text/plain" });
res.end(err);
}
res.writeHead(200, { "Content-Type": "application/json" });
res.end(JSON.stringify({code: 200, data: '/upload/' + name}));
});
});
} else if (req.url === "/user-ajax") {
const html = fs.readFileSync("./upload.ajax.html");
res.writeHead(200, { "Content-Type": "text/html; charset=UTF8" });
res.end(html);
} else if (req.url === "/user-form") {
const html = fs.readFileSync("./upload.form.html");
res.writeHead(200, { "Content-Type": "text/html; charset=UTF8" });
res.end(html);
} else if (req.url === "/upload-ok") {
const html = fs.readFileSync("./upload.ok.html");
res.writeHead(200, { "Content-Type": "text/html; charset=UTF8" });
res.end(html);
} else {
res.writeHead(200, { "Content-Type": "text/html; charset=UTF8" });
res.end("No found!");
}
})
.listen(7777);
3. 兩種提交方式的不同
表單提交成功后, 直接跳轉到了 /upload 返回 { code: 200, data: '/upload/XXXXX.png' }
ajax異步提交成功后, 是返回 json 數據, 頁面不刷新.
這里的處理方案, 如果是用form表單提交, 可以修改后端返回直接重定向到一個提交成功頁面(upload.ok.html)
// ajax提交 成功之后返回 json
// res.writeHead(200, { "Content-Type": "application/json" });
// res.end(JSON.stringify({code: 200, data: '/upload/' + name}));
// form表單 成功之后 重定向頁面
res.writeHead(302, { 'Location': './upload-ok'})
4. 補充說明
這里博主 試着抓取 ajax 與 form表單 兩種提交方式的 req 對象對比, 在 本機 localhost 的環境下 是有一個 Sec-fetch-mode 的值的別去 form 是 navigate , ajax 是 cors , 但是走網絡請求后 是沒有 Sec-fetch-mode ,實在找不到兩者如何來區分;
記得Express.js 框架提供一個 req.xhr 屬性,如果請求由 Ajax 發起將會返回 true , 后期研究之后再補充;
5. 資料來源指向 .