Node.js实现文件上传


Posted in Javascript onJuly 05, 2016

在工作中碰到了这样的需求,需要用nodejs 来上传文件,之前也只是知道怎么通过浏览器来上传文件, 用nodejs的话, 相当于模拟浏览器的行为。 google 了一番之后, 明白了浏览器无非就是利用http协议来给服务器传输数据, 具体协议就是《RFC 1867 - Form-based File Upload in HTML》, 在浏览器上通过form 表单来上传文件就是通过这个协议,我们可以先看看浏览器给服务端发送了什么数据, 就可以依葫芦画瓢的把上传功能实现出来。说起form 表单上传文件的话, 大家应该很熟悉:

<form action="http://www.qq.com/" method="post">
<input type="text" name="text1" /><br />
<input type="text" name="text2" /><br />
<input type="submit" />
</form>

提交时, 用fiddler 抓包可以看到向服务端发出这样的数据:

POST http://www.qq.com/ HTTP/1.1
Host: www.qq.com
Content-Length: 23
Content-Type: application/x-www-form-urlencoded; charset=UTF-8

text1=hello&text2=world

值得注意的是Content-Type默认为application/x-www-form-urlencoded,所以消息会经过URL编码。比如“你好”会编码为 %E4%BD%A0%E5%A5%BD。

接下来我们看一下通过form 表单是怎么上传的。大家应该也不陌生:

<form action="http://www.qq.com" method="post" enctype="multipart/form-data">
<input type="file" name="myfile" />
<input type="submit" value="submit" />
</form>

然后新建一个只有hello world字样的upload.txt文本文件上传上去,我们再吃用fiddler 来抓下包, 可以发现发送过去的数据稍微复杂了一些(已经去掉了很多的其它没关系的请求行,比如缓存控制和cookie之类的):

POST http://www.qq.com/ HTTP/1.1
Host: www.qq.com
Content-Length: 199
Content-Type: multipart/form-data; boundary=----WebKitFormBoundarywr3X7sXBYQQ4ZF5G

------WebKitFormBoundarywr3X7sXBYQQ4ZF5G
Content-Disposition: form-data; name="myfile"; filename="upload.txt"
Content-Type: text/plain

hello world

------WebKitFormBoundarywr3X7sXBYQQ4ZF5G--

根据RFC 1867的定义,我们需要生成一段边界数据,这个数据不能在内容的其它地方出现,这个可以自己定义, 在每个浏览器的生成算法可能都不一样, 上面的boundary就是分隔数据,生成了分隔数据之后, 就可以把分隔数据放在头部的Content-Type里面传送给服务端, 也就是上文的 Content-Type: multipart/form-data; boundary=----WebKitFormBoundarywr3X7sXBYQQ4ZF5G, 另外,上传的内容,需要用分隔数据来分隔成若干个段,然后每段数据里面都有文件的文件名,还有上传时候的name,服务端就是用这个name来接收文件,还有文件的类型Content-Type,在这个例子里是 text/plain,如果上传的是png图片就是image/png。文件类型的一个空行后就是所上传的文件的内容,在这个例子里也是为了容易理解所以上传的是文本文件所以内容直接就能够显示出来,如果上传的是图片文件, 因为是二进制文件,fiddler 就显示的是乱码。 文件的内容结束之后就是一个空行再加上边界数据。

了解了发送格式的细节之后, 下一步就是使用nodejs来编程实现,简单来讲, 就是按照格式把数据发送给服务端就行了。

const http = require('http');
const fs = require('fs');
//post地址为本地服务的一个php,用于测试上传是否成功
var options = {
hostname: 'localhost',
port: 80,
path: '/get.php',
method: 'POST'
}
//生成分隔数据
var boundaryKey = '----WebKitFormBoundaryjLVkbqXtIi0YGpaB'; 
//读取需要上传的文件内容
fs.readFile('./upload.txt', function (err, data) {
//拼装分隔数据段
var payload = '--' + boundaryKey + '\r\n' + 'Content-Disposition:form-data; name="myfile"; filename="upload.txt"\r\n' + 'Content-Type:text/plain\r\n\r\n';
payload += data;
payload += '\r\n--' + boundaryKey + '--';
//发送请求
var req = http.request(options, function (res) {
res.setEncoding('utf8');
res.on('data', function (chunk) {
console.log('body:' + chunk);
});
});
req.on('error', function(e) {
console.error("error:"+e);
});
//把boundary、要发送的数据大小以及数据本身写进请求
req.setHeader('Content-Type', 'multipart/form-data; boundary='+boundaryKey+'');
req.setHeader('Content-Length', Buffer.byteLength(payload, 'utf8'));
req.write(payload);
req.end();
});

本文重点在于了解协议并且用代码实现出来, 代码组织上面还有很多优化的地方。

最后在本地apache,简单写一个php来保存上传的文件来用作测试:

<?php
$filePath = './upload.txt';
move_uploaded_file($_FILES['myfile']['tmp_name'] , $filePath);
echo "ok";
?>

另外,根据RFC 1867 还可以实现一次上传多个文件的功能, 这个在这里就不详述, 需要的话可以详细参考RFC 1867来实现。

以上所述是小编给大家介绍的Node.js实现文件上传,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Javascript 相关文章推荐
jQuery 添加/移除CSS类实现代码
Feb 11 Javascript
jquery异步调用页面后台方法&amp;#8207;(asp.net)
Mar 01 Javascript
一个简单的动态加载js和css的jquery代码
Sep 01 Javascript
jQuery表单美化插件jqTransform使用详解
Apr 12 Javascript
PassWord输入框代码分享
Jun 07 Javascript
jQuery实现选项卡功能(两种方法)
Mar 08 Javascript
ionic2自定义cordova插件开发以及使用(Android)
Jun 19 Javascript
javascript兼容性(实例讲解)
Aug 15 Javascript
利用百度地图API获取当前位置信息的实例
Nov 06 Javascript
JS无限级导航菜单实现方法
Jan 05 Javascript
js实现3D粒子酷炫动态旋转特效
Sep 13 Javascript
element-ui封装一个Table模板组件的示例
Jan 04 Javascript
JavaScript数组方法大全(推荐)
Jul 05 #Javascript
JS与HTML结合使用marquee标签实现无缝滚动效果代码
Jul 05 #Javascript
js利用正则表达式检验输入内容是否为网址
Jul 05 #Javascript
后端接收不到AngularJs中$http.post发送的数据原因分析及解决办法
Jul 05 #Javascript
微信JS-SDK坐标位置如何转换为百度地图坐标
Jul 04 #Javascript
Bootstrap实现水平排列的表单
Jul 04 #Javascript
JSONP跨域请求实例详解
Jul 04 #Javascript
You might like
jQuery+PHP+ajax实现微博加载更多内容列表功能
2014/06/27 PHP
php如何获取文件的扩展名
2015/10/28 PHP
PHP获取用户访问IP地址的5种方法
2016/05/16 PHP
PHP线程的内存回收问题
2016/07/08 PHP
PHP执行系统命令函数实例讲解
2021/03/03 PHP
js 父窗口控制子窗口的行为-打开,关闭,重定位,回复
2010/04/20 Javascript
基于JQuery的Select选择框的华丽变身
2011/08/23 Javascript
用JQuery实现全选与取消的两种简单方法
2014/02/22 Javascript
不得不分享的JavaScript常用方法函数集(上)
2015/12/23 Javascript
localStorage实现便签小程序
2016/11/28 Javascript
jQuery Ajax使用FormData上传文件和其他数据后端web.py获取
2017/06/11 jQuery
详解如何实现一个简单的Node.js脚手架
2017/12/04 Javascript
JS+canvas画一个圆锥实例代码
2017/12/13 Javascript
详解基于Vue/React项目的移动端适配方案
2019/08/23 Javascript
vue实现的封装全局filter并统一管理操作示例
2020/02/02 Javascript
vue 接口请求地址前缀本地开发和线上开发设置方式
2020/08/13 Javascript
[04:10]2018年度CS GO玩家最喜爱的主播-完美盛典
2018/12/16 DOTA
python paramiko实现ssh远程访问的方法
2013/12/03 Python
python中assert用法实例分析
2015/04/30 Python
分享6个隐藏的python功能
2017/12/07 Python
python处理csv数据动态显示曲线实例代码
2018/01/23 Python
python爬虫-模拟微博登录功能
2019/09/12 Python
python实现文件批量编码转换及注意事项
2019/10/14 Python
python图形开发GUI库wxpython使用方法详解
2020/02/14 Python
python numpy--数组的组合和分割实例
2020/02/24 Python
使用OpenCV去除面积较小的连通域
2020/07/05 Python
css3 box-sizing属性使用参考指南
2013/01/08 HTML / CSS
英文自我鉴定
2013/12/10 职场文书
大学生通用个人的自我评价
2014/02/10 职场文书
文秘大学生求职信
2014/02/25 职场文书
腾讯广告词
2014/03/19 职场文书
经贸专业毕业生求职信
2014/03/23 职场文书
广场舞大赛策划方案
2014/05/31 职场文书
班组长安全工作职责
2014/07/15 职场文书
党的群众路线教育实践活动心得体会(乡镇)
2014/11/03 职场文书
golang特有程序结构入门教程
2021/06/02 Python