浅析Node.js实现HTTP文件下载


Posted in Javascript onAugust 05, 2016

前言

HTTP实现文件下载时,只要在服务器设置好相关响应头,并使用二进制传输文件数据即可,而客户端(浏览器)会根据响应头接收文件数据。而在Node.js中,设置好响应头后,读取文件流,再使用“.pipe()”方法将流转接到响应对象Response就可以实现一个简单的文件下载服务器。

1. 文件下载介绍

HTTP基于请求头和响应头实现状态交互,在得到服务器正确响应状态后,而客户端首先会解析响应头,并根据响应头来接收和展示数据(响应体)。对于文件下载来说,其实现过程如下:

    1.客户端发起文件资源请求

    2.服务器查找对应文件,并设置”Content-Type”、”Content-Disposition”等响应头,分别用于表示文件的”MIME”类型及文件描述

    3.客户端根据服务器返回的响应头解析和接收文件数据

需要设置的响应头

设置文件下载响应头时,除了常用的HTTP响应头外,比较重要是还要设置以下两个响应头:

Content-Type: application/octet-stream
Content-Disposition: attachment; filename=MyFileName.ext

在上面的设置中,”Content-Type: application/octet-stream”告诉浏览器这是一个二进制文件,”Content-Disposition”告诉浏览器这是一个需要下载的附件并告诉浏览器默认的文件名。如果不添加”Content-Disposition”响应头,浏览器可能会下载或显示文件内容,不同浏览器的处理有所不同。

2. Node.js文件下载服务器实现

接下来我们基于Express 框架实现一个简单文件下载服务器,在这个服务器中主要包括两个功能:服务器文件的浏览文件的下载

2.1 添加路由

创建Express应用后,添加如下两个路由:

router.get('/files', function(req, res, next) {
 // 显示服务器文件 
});
router.get('/file/:fileName', function(req, res, next) {
 // 实现文件下载 
});

上面的添加的两个路由分别用于:显示服务器文件、实现文件下载

2.2 显示服务器文件

实现服务器文件的显示,要通过”fs”模块读取文件目录并进行文件/目录检查等。还需要使用”path”模块处理文件路径。首先引入这两个模块:

const fs = require('fs');
const path = require('path');

显示服务器文件实现代码如下:

router.get('/files', function(req, res, next) {
 // 显示服务器文件 
 // 文件目录
 var filePath = path.join(__dirname, './');
 fs.readdir(filePath, function(err, results){
  if(err) throw err;
  if(results.length>0) {
   var files = [];
   results.forEach(function(file){
   if(fs.statSync(path.join(filePath, file)).isFile()){
     files.push(file);
   }
   })
   res.render('files', {files:files});
  } else {
   res.end('当前目录下没有文件');
  }
 });
});

上面代码中,读取目录后通过视图文件”files.ejs”显示可下载文件列表。其代码如下:

<!DOCTYPE html>
<html>
 <head>
  <title>下载文件选择</title>
 </head>
 <body>
  <h1>请选择下载文件:</h1>
  <% if(files.length>0) {%>
  <ul>
   <% files.forEach(function(file){ %>
   <li>
    <a href="/file/<%- file %>" target="_blank"><%- file %></a>
   </li>
   <%})%>
  </ul>
  <%} else {%>
  <p>没有可下载文件…</p>
  <%}%>
 </body>
</html>

2.3 实现文件下载

实现文件下载时,可以先读取文件到一个”Buffer”中,再通过”res.send()”或”res.end()”方法发送文件数据,也可以基于流(”Stream”)实现文件数据的发送。使用”Stream”实现文件下载时,可以使用”fs.createReadStream()”方法创建一个可读流,而响应对象Response是一个可写流。这样,只需要通过”.pipe()”方法将文件流转接到Response响应流中即可。

文件下载实现代码如下:

router.get('/file/:fileName', function(req, res, next) {
 // 实现文件下载 
 var fileName = req.params.fileName;
 var filePath = path.join(__dirname, fileName);
 var stats = fs.statSync(filePath); 
 if(stats.isFile()){
  res.set({
   'Content-Type': 'application/octet-stream',
   'Content-Disposition': 'attachment; filename='+fileName,
   'Content-Length': stats.size
  });
  fs.createReadStream(filePath).pipe(res);
 } else {
  res.end(404);
 }
});

总结

以上就是利用Node.js实现HTTP文件下载的全部内容,希望对大家学习Node.js有所帮助。

Javascript 相关文章推荐
js中将多个语句写成一个语句的两种方法小结
Dec 08 Javascript
js tab 选项卡
Apr 26 Javascript
禁用JavaScript控制台调试的方法
Mar 07 Javascript
初步认识JavaScript函数库jQuery
Jun 18 Javascript
JavaScript实现文本框中默认显示背景图片在获得焦点后消失的方法
Jul 01 Javascript
几种经典排序算法的JS实现方法
Mar 25 Javascript
JavaScript数组方法总结分析
May 06 Javascript
Vue.js绑定HTML class数组语法错误的原因分析
Oct 19 Javascript
Vue非父子组件通信详解
Jun 12 Javascript
JS使用Dijkstra算法求解最短路径
Jan 17 Javascript
微信小程序云开发实现数据添加、查询和分页
May 17 Javascript
详解vue 自定义组件使用v-model 及探究其中原理
Oct 11 Javascript
JS中对Cookie的操作详解
Aug 05 #Javascript
jQuery插件EasyUI获取当前Tab中iframe窗体对象的方法
Aug 05 #Javascript
js实现精确到毫秒的倒计时效果
Aug 05 #Javascript
jQuery实现Select左右复制移动内容
Aug 05 #Javascript
jQuery插件EasyUI实现Layout框架页面中弹出窗体到最顶层效果(穿越iframe)
Aug 05 #Javascript
jQuery插件EasyUI设置datagrid的checkbox为禁用状态的方法
Aug 05 #Javascript
基于HTML+CSS+JS实现增加删除修改tab导航特效代码
Aug 05 #Javascript
You might like
php实现天干地支计算器示例
2014/03/14 PHP
php进行支付宝开发中return_url和notify_url的区别分析
2014/12/22 PHP
php编译安装php-amq扩展简明教程
2016/06/25 PHP
PHP二维关联数组的遍历方式(实例讲解)
2017/10/18 PHP
thinkPHP框架自动填充原理与用法分析
2018/04/03 PHP
php微信公众号开发之秒杀
2018/10/20 PHP
点击广告后才能获得下载地址
2006/10/26 Javascript
JQuery扩展插件Validate—4设置错误提示的样式
2011/09/05 Javascript
js函数返回多个返回值的示例代码
2013/11/05 Javascript
浅谈JavaScript函数参数的可修改性问题
2013/12/05 Javascript
javascript实现的一个带下拉框功能的文本框
2014/05/08 Javascript
node.js中的fs.chownSync方法使用说明
2014/12/16 Javascript
轻松创建nodejs服务器(8):非阻塞是如何实现的
2014/12/18 NodeJs
在JavaScript中模拟类(class)及类的继承关系
2016/05/20 Javascript
Vue底层实现原理总结
2018/02/17 Javascript
vue2.0 自定义组件的方法(vue组件的封装)
2018/06/05 Javascript
JS闭包原理与应用经典示例
2018/12/20 Javascript
简单掌握Python的Collections模块中counter结构的用法
2016/07/07 Python
Python算法应用实战之队列详解
2017/02/04 Python
python3库numpy数组属性的查看方法
2018/04/17 Python
python socket 聊天室实例代码详解
2019/11/14 Python
基于spring boot 日志(logback)报错的解决方式
2020/02/20 Python
详解pytorch中squeeze()和unsqueeze()函数介绍
2020/09/03 Python
一篇文章带你搞定Ubuntu中打开Pycharm总是卡顿崩溃
2020/11/02 Python
曼联官方网上商店:Manchester United Direct
2017/07/28 全球购物
一封普通求职者的求职信
2013/11/20 职场文书
财务管理专业自荐信范文
2013/12/24 职场文书
《桂花雨》教学反思
2014/04/12 职场文书
建筑专业毕业生求职信
2014/09/30 职场文书
2014年服务员个人工作总结
2014/12/23 职场文书
饭店服务员岗位职责
2015/02/09 职场文书
库房管理员岗位职责
2015/02/12 职场文书
新闻稿件写作范文
2015/07/18 职场文书
Java并发编程必备之Future机制
2021/06/30 Java/Android
Python实现滑雪小游戏
2021/09/25 Python
Spring Data JPA框架持久化存储数据到数据库
2022/04/28 Java/Android