http文件服务器上传文件,Node.js HTTP服务器中的文件、图片上传的方法

HTTP协议中,multipart/form-data格式用于向服务器发送二进制数据,通过这一内容类型(Content-Type)可以实现文件、图片的上传。由于这种格式发送的是二进制数据,在服务器端接收和处理数据时会与其它内容类型有所有区别。

HTTP协议中的文件上传

最早的HTTP协议中是不支持文件上传的,在1995年制定的rfc1867规范中,在HTTP POST请求的内容类型Content-Type中扩展了multipart/form-data类型,该类型用于向服务器发送二进制数据,以便支持文件的上传。

POST上传文件

我们通过form表单提交文件时,会构造类似像下面这样一个表单:

在使用form提交表单数据时,默认的编码格式为application/x-www-form-urlencoded,上传文件时需要通过enctype属性将编码方式设置为multipart/form-data。

HTTP数据提交与服务器数据解析

在包含请求体的请求中,提交的数据会按指定编码类型进行编码,而客户端会按编码方式设置请求头中的Content-Type字段。

在一个application/x-www-form-urlencoded编码的请求中,会设置一个如下的请求头:

Content-Type:application/x-www-form-urlencoded

而用于文件上传的编码方式multipart/form-data,会设置一个如下的请求头:

Content-type: multipart/form-data, boundary=AaB03x

服务器数据接收与解析

对于一个编码方式为application/x-www-form-urlencoded的请求来说,会对提交内容进行URL编码。服务器会收到类似如下内容:

POST / HTTP/1.1

Content-Type: application/x-www-form-urlencoded

Accept-Encoding: gzip, deflate

Host: itbilu.com

Content-Length: 23

Connection: Keep-Alive

Cache-Control: max-age=0

key1=value1&key2=value2

请求头与请求体之间会有一个空行,服务器会对请求体以queryString的方式进行解码。

而对一个multipart/form-data的文件上传请求来说,收到的内容类似如下:

POST / HTTP/1.1

Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryYN9YYwO9ESipYBIx

Accept-Encoding: gzip, deflate

Host: itbilu.com

Content-Length: 22646

Connection: Keep-Alive

Cache-Control: max-age=0

------WebKitFormBoundaryoqBx9oYBhx4SF1YQ

Content-Disposition: form-data; name="myName"

itbilu.com

------WebKitFormBoundaryYN9YYwO9ESipYBIx

Content-Disposition: form-data; name="upload"; filename="41GiLecHO3L.jpg"

Content-Type: image/jpeg

����JFIF��C // 文件的二进制数据

……

--------WebKitFormBoundaryYN9YYwO9ESipYBIx--

在请求头的Content-Type字段中,除了编码类型为multipart/form-data描述外,还有一个boundary属性,这是客户端随机生成的一个数据边界描述。

如上所示,文件上传时内容是分段传输的,每一boundary表示一个fild(form表单控值)边界。

如上面示例所示,上传文件时除内容描述外还包含一个的Content-Type文件MIME的描述,其后是一个空行和文件的二进制数据。所有的表单数据结束后,会有一个”–”+boundary+”–”结束符。而服务器接收到数据后,同样会根据boundary来进行数据的接收和解析。

Node.js中处理图片/文件上传

Node.js中处理文件上传的第三方模块,本站曾经介绍过使用formidable模块处理文件上传,下面简单介绍使用Node.js原生环境处理图片上传,上传文件时也可以参考处理。

首先,使用Node.js的HTTP模块创建一个HTTP服务器:

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('其它提交方式');

}

}).listen(3000);

在这一步中,我们创建HTTP 服务器,当GET请求时,会加载一上用于文件上传的form表单。上传文件会通过POST方式提交到服务器,这时服务端会通过parseFile函数解析并保存文件,其解析代码如下:

function parseFile (req, res) {

req.setEncoding('binary');

var body = ''; // 文件数据

var fileName = ''; // 文件名

// 边界字符串

var boundary = req.headers['content-type'].split('; ')[1].replace('boundary=','');

req.on('data', function(chunk){

body += chunk;

});

req.on('end', function() {

var 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))

var entireData = body.toString();

var contentTypeRegex = /Content-Type: image\/.*/;

contentType = file['Content-Type'].substring(1);

//获取文件二进制数据开始位置,即contentType的结尾

var upperBoundary = entireData.indexOf(contentType) + contentType.length;

var shorterData = entireData.substring(upperBoundary);

// 替换开始位置的空格

var binaryDataAlmost = shorterData.replace(/^\s\s*/, '').replace(/\s\s*$/, '');

// 去除数据末尾的额外数据,即: "--"+ boundary + "--"

var binaryData = binaryDataAlmost.substring(0, binaryDataAlmost.indexOf('--'+boundary+'--'));

// 保存文件

fs.writeFile(fileName, binaryData, 'binary', function(err) {

res.end('图片上传完成');

});

} else {

res.end('只能上传图片文件');

}

});

}

req是一个IncomingMessage对象,而该对象又实现了ReadableStream,所以我们可以用流的方式来接收数据。数据接收完成了,按rfc1867规范进行了数据处理,并通过fs模块保存了文件。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值