十年网站开发经验 + 多家企业客户 + 靠谱的建站团队
量身定制 + 运营维护+专业推广+无忧售后,网站问题一站解决
本篇文章给大家分享的是有关怎么在node中对文件上传接口进行转发,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。
创新互联公司是一家专注于成都网站建设、网站设计与策划设计,大宁网站建设哪家好?创新互联公司做网站,专注于网站建设十载,网设计领域的专业建站公司;建站业务涵盖:大宁等地区。大宁做网站价格咨询:028-86922220
js 中的文件
web 中的 Blob 、File 和 Formdate
一个 Blob ( Binary Large Object ) 对象表示一个不可变的, 原始数据的类似文件对象。Blob表示的数据不一定是一个JavaScript原生格式。 File 接口基于Blob,继承 Blob 功能并将其扩展为支持用户系统上的文件。
前端上传文件的方式无非就是使用:1、表单自动上传;2、使用 ajax 上传。我们可以使用以下代码创建一个 Form,并打印出 file

从 F12 中可以看出 File 原型链上是 Blob。
简单地说 Blob 可以理解为 Web 中的二进制文件。 而 File 是基于 Blob 实现的一个类,新增了关于文件有关的一些信息。
FormData对象的作用就类似于 Jq 的 serialize() 方法,不过 FormData 是浏览器原生的,且支持二进制文件。 ajax 通过 FormData 这个对象发送表单请求,无论是原生的 XMLHttpRequest 、jq 的 ajax 方法、 axios 都是在 data 里直接指定上传 formData 类型的数据,fetch api 是在 body 里上传。
forData 数据有两种方式生成,如下 formData 和 formData2 的区别,而 formData2 可以通过传入一个 element 的方式进行初始化,初始化之后依然可以调用 formData 的 append 方法。
console.log() 无法直接打印出 formData 的数据,可以使用 get(key) 或者 getAll(key)
如果是使用 new FormData(element) 的创建方式,上面 key 为 上的 name 字段。
如果是使用 append 添加的数据,get/getAll 时 key 为 append 所指定的 key。
node 中的 Buffer 、 Stream 、fs
Buffer 和 Stream 是 node 为了让 js 在后端拥有处理二进制文件而出现的数据结构。
通过名字可以看出 buffer 是缓存的意思。存储在内存当中,所以大小有限,buffer 是 C++ 层面分配的,所得内存不在 V8 内。
stream 可以用水流形容数据的流动,在文件 I/O、网络 I/O中数据的传输都可以称之为流。
通过两个 fs 的 api 看出,readFile 不指定字符编码默认返回 buffer 类型,而 createReadStream 将文件转化为一个 stream , nodejs 中的 stream 通过 data 事件能够一点一点地拿到文件内容,直到 end 事件响应为止。
const fs = require("fs");
fs.readFile("./package.json", function(err, buffer) {
if (err) throw err;
console.log("buffer", buffer);
});
function readLines(input, func) {
var remaining = "";
input.on("data", function(data) {
remaining += data;
var index = remaining.indexOf("\n");
var last = 0;
while (index > -1) {
var line = remaining.substring(last, index);
last = index + 1;
func(line);
index = remaining.indexOf("\n", last);
}
remaining = remaining.substring(last);
});
input.on("end", function() {
if (remaining.length > 0) {
func(remaining);
}
});
}
function func(data) {
console.log("Line: " + data);
}
var input = fs.createReadStream("./package.json");
input.setEncoding("binary");
readLines(input, func);fs.readFile() 函数会缓冲整个文件。 为了最小化内存成本,尽可能通过 fs.createReadStream() 进行流式传输。
使用 nodejs 创建 uoload api
http 协议中的文件上传
在 http 的请求头中 Content-type 是 multipart/form-data时,请求的内容如下:
POST / HTTP/1.1 Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryoMwe4OxVN0Iuf1S4 Origin: http://localhost:3000 Referer: http://localhost:3000/upload Sec-Fetch-Mode: navigate Sec-Fetch-User: ?1 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36 ------WebKitFormBoundaryoqBx9oYBhx4SF1YQ Content-Disposition: form-data; name="upload" http://localhost:3000 ------WebKitFormBoundaryoMwe4OxVN0Iuf1S4 Content-Disposition: form-data; name="upload"; filename="IMG_9429.JPG" Content-Type: image/jpeg ����JFIF��C // 文件的二进制数据 …… --------WebKitFormBoundaryoMwe4OxVN0Iuf1S4--
根据 WebKitFormBoundaryoMwe4OxVN0Iuf1S4 可以分割出文件的二进制内容
原生 node
使用原生的 node 写一个文件上传的 demo
const http = require("http");
const fs = require("fs");
const util = require("util");
const querystring = require("querystring");
//用http模块创建一个http服务端
http
.createServer(function(req, res) {
if (req.url == "/upload" && req.method.toLowerCase() === "get") {
//显示一个用于文件上传的form
res.writeHead(200, { "content-type": "text/html" });
res.end(
'"
);
} else if (req.url == "/upload" && req.method.toLowerCase() === "post") {
if (req.headers["content-type"].indexOf("multipart/form-data") !== -1)
parseFile(req, res);
} else {
res.end("pelease upload img");
}
})
.listen(3000);
function parseFile(req, res) {
req.setEncoding("binary");
let body = ""; // 文件数据
let fileName = ""; // 文件名
// 边界字符串 ----WebKitFormBoundaryoMwe4OxVN0Iuf1S4
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", ":");
// 只处理图片文件;
if (file["Content-Type"].indexOf("image") !== -1) {
//获取文件名
var fileInfo = file["Content-Disposition"].split("; ");
for (value in fileInfo) {
if (fileInfo[value].indexOf("filename=") != -1) {
fileName = fileInfo[value].substring(10, fileInfo[value].length - 1);
if (fileName.indexOf("\\") != -1) {
fileName = fileName.substring(fileName.lastIndexOf("\\") + 1);
}
console.log("文件名: " + fileName);
}
}
// 获取图片类型(如:image/gif 或 image/png))
const entireData = body.toString();
const contentTypeRegex = /Content-Type: image\/.*/;
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 + "--")
);
// console.log("binaryData", binaryData);
const bufferData = new Buffer.from(binaryData, "binary");
console.log("bufferData", bufferData);
// fs.writeFile(fileName, binaryData, "binary", function(err) {
// res.end("sucess");
// });
fs.writeFile(fileName, bufferData, function(err) {
res.end("sucess");
});
} else {
res.end("reupload");
}
});
}通过 req.setEncoding("binary"); 拿到图片的二进制数据。可以通过以下两种方式处理二进制数据,写入文件。
fs.writeFile(fileName, binaryData, "binary", function(err) {
res.end("sucess");
});fs.writeFile(fileName, bufferData, function(err) {
res.end("sucess");
});koa
在 koa 中使用 koa-body 可以通过 ctx.request.files 拿到上传的 file 对象。下面是例子。
'use strict';
const Koa = require('koa');
const app = new Koa();
const router = require('koa-router')();
const koaBody = require('../index')({multipart:true});
router.post('/users', koaBody,
(ctx) => {
console.log(ctx.request.body);
// => POST body
ctx.body = JSON.stringify(ctx.request.body, null, 2);
}
);
router.get('/', (ctx) => {
ctx.set('Content-Type', 'text/html');
ctx.body = `