1. 技术栈前端/后端 原生JS
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. 资料来源指向