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. 资料来源指向 .