1、文件上传
1.1 后端代码实现
const http = require('http');
const querystring = require("querystring");
const fs = require('fs');
const server = http.createServer((req, res) => {
// 处理跨域请求
res.setHeader('Access-Control-Allow-Origin', '*');
if (req.url === '/upload') {
if (req.method.toLowerCase() === 'get') {
// 返回一个用于文件上传的form
res.writeHead(200, { 'content-type': 'text/html' });
res.end(
`
<form action="upload" enctype="multipart/form-data" method="POST">
<input type="file" name="upload" multiple="multiple" />
<input type="submit" value="Upload" />
</form>
`
)
} else if (req.method.toLowerCase() === 'post') {
if (req.headers['content-type'].indexOf('multipart/form-data') !== -1) {
parseFormData(req, res);
} else {
res.end('你好')
}
}
}
});
function parseFormData (req, res) {
req.setEncoding('binary');
let body = ''; // 文件数据
let fileName = ''; // 文件名
// 边界字符串
const boundary = req.headers['content-type']
.split('; ')[1]
.replace('boundary=', '');
req.on('data', function (chunk) {
body += chunk;
});
req.on("end", function() {
const file = querystring.parse(body, "\r\n", ":");
const fileInfo = file["Content-Disposition"].split(";");
for (value in fileInfo) {
if (fileInfo[value].indexOf("filename=") !== -1) {
fileName = fileInfo[value].substring(11, fileInfo[value].length - 1);
// 这是处理什么情况的?
if (fileName.indexOf("\\") != -1) {
fileName = fileName.substring(fileName.lastIndexOf("\\") + 1);
}
break
}
}
const entireData = body.toString();
contentType = file["Content-Type"].substring(1);
//获取文件二进制数据开始位置,即contentType的结尾
const upperBoundary = entireData.indexOf(contentType) + contentType.length;
const shorterData = entireData.substring(upperBoundary);
// 替换开始位置的空格
const binaryDataAlmost = shorterData
.replace(/^\s\s*/, "")
.replace(/\s\s*$/, "");
// 去除数据末尾的额外数据,即: "--"+ boundary + "--"
const binaryData = binaryDataAlmost.substring(0, binaryDataAlmost.indexOf("--" + boundary + "--"));
const bufferData = new Buffer.from(binaryData, "binary");
fs.writeFile(fileName, bufferData, function(err) {
if (err) {
console.log(err);
}
res.end("sucess");
});
});
}
server.listen(3001);
这里处理formData数据时没有使用中间件进行处理,所以有点麻烦(中间件处理方案后续补上)。 参考链接:原生nodejs 处理文件上传
1.2 前端代码实现
1.2.1 <form>表单提交
代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body>
<form
action="http://localhost:3001/upload"
method="POST"
enctype="multipart/form-data"
>
<input type="file" name="file" id="">
<input type="submit" value="提交">
</form>
</body>
</html>
form有关提交表单的属性
补充一下,好久不写,都不记得了
action:处理表单提交的URL。可被<button>、<input type="submit">或<input type="image">元素上的formaction属性覆盖enctype:当method属性值为post时,enctype就是将表单内容提交给服务器的MIME类型;可选:application/x-www-form-urlencoded(默认),multipart/form-data(表单包含type=file的input元素时使用),text/plain(出现于HTML5,用于调试,可被<button>、<input type="submit">或<input type="image">元素上的formenctype属性覆盖)method:可选值:post,get,dialog(如果表单在<dialog>元素中,提交时关闭对话框。此值可以被<button>或<input type="image">元素中的formmethod属性覆盖。)novalidate:表示提交表单时不需要验证表单;该属性可以被表单中的<button>、<input type="submit">或<input type="image">元素中的formnovalidate属性覆盖。target:表示提交表单后,在哪里显示响应信息
参考链接:form
注意:
form表单提交不存在跨域问题
1.2.2 原生XmlHttpRequest上传文件
代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body>
<input type="file" id="upload">
<button class="upload-btn">点击上传</button>
<script>
const btn = document.querySelector('.upload-btn');
btn.addEventListener('click', function (e) {
let xhr;
if (window.XMLHttpRequest) {
xhr = new XMLHttpRequest();
} else {
// 兼容IE
xhr = ActiveXObject('Microsoft.XMLHTTP');
}
let fd = new FormData();
const file = document.querySelector('#upload');
console.log(file.files);
fd.append('file', file.files[0]);
// 初始化
console.log('UNSEDN', xhr.readyState);
// 打开连接
xhr.open('post', 'http://localhost:3001/upload');
// xhr.setRequestHeader('Content-Type', 'multipart/form-data');
xhr.send(fd);
xhr.onreadystatechange = function () {
if(this.readyState === 2){
// 接收到响应头
console.log("HEADERS_RECEIVED",xhr.readyState);
}else if(this.readyState === 3){
// 响应体加载中
console.log("LOADING",xhr.readyState);
}else if(this.readyState === 4){
// 加载完成
console.log("DONE",xhr.readyState);
}
}
});
</script>
</body>
</html>
1.2.3 jQuery实现
代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js"></script>
</head>
<body>
<input type="file" id="upload">
<input class="upload-btn" type="button" value="点击上传" />
<script>
$('.upload-btn').click(function (e) {
const fd = new FormData();
console.log($('#upload')[0].files[0]);
const file = $('#upload')[0].files[0]
fd.append('file', file);
$.ajax({
url: 'http://localhost:3001/upload',
type: 'post',
data: fd,
contentType: false,
processData: false,
success: function (e) {
console.log(e);
}
})
})
</script>
</body>
</html>
1.2.4 axios 实现
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script></head>
<body>
<input type="file" id="upload">
<input class="upload-btn" type="button" value="点击上传" />
<script>
const btn = document.querySelector('.upload-btn');
btn.addEventListener('click', function () {
const file = document.querySelector('#upload').files[0];
const fd = new FormData();
fd.append('file', file);
axios.post('http://localhost:3001/upload', fd).then(res => {
console.log(res);
}).catch(e => {
console.error(e);
});
return false;
});
</script>
</body>
</html>