文件下载方式

方式一:通过返回二进制数据blob进行下载、后端res.download返回
前端:

fetch("/down")
  .then(res => res.blob())  fetch方式
  .then(blob => {
    down(blob, "demo.pdf");
 });

 var xhr = new XMLHttpRequest();
    xhr.open(method, url);
    
    xhr.responseType = "arraybuffer";  ajax方式
    或
    xhr.responseType = "blob";
    xhr.onreadystatechange = function() {
      if (xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) {
        resolve(xhr.response);
      }
    };
    xhr.send();

后端:

app.get('/down',(req,res)=>{
 	 res.download('demo.pdf')
}

方式二:后端通过流的方式

router.use('/downloadFile', (req, res, next) => {
    var filename = req.query.filename;
    var oldname = req.query.oldname;
    var file = './uploads/' + filename;
    res.writeHead(200, {
        'Content-Type': 'application/octet-stream',//告诉浏览器这是一个二进制文件
        'Content-Disposition': 'attachment; filename=' + encodeURI(oldname),//告诉浏览器这是一个需要下载的文件
    });//设置响应头
    var readStream = fs.createReadStream(file);//得到文件输入流

    readStream.on('data', (chunk) => {
        res.write(chunk, 'binary');//文档内容以二进制的格式写到response的输出流
    });
    readStream.on('end', () => {
        res.end();
    })
})

流下载+axios

const fs = require('fs')
const http = require('http')
// 必用模块引用 ↑

const server = http.createServer((req, res) => {
	const { method, url } = req // 获取请求地址 以及请求方式
	if(method === 'post' && url === '/dow') {
		const size = fs.statSync('./res_file.txt').size; // 获取文件大小
		const headers = {
		  'Content-type': 'application/octet-stream', // 声明二进制文件流格式
		  'Content-Disposition': 'attachment;filename=res_file.txt', // 自定义文件名称
		  'Content-Length': size // 设置文件大小 【如果不设置这个,前端想实现进度条类似的功能,可能获取不到文件的总大小噢】
		}
		const filsPath = fs.createReadStream('./res_file.txt').pipe(res) // 获取文件
		filsPath.on('data', (data) => {
			res.write(data, 'binary')
		}).on('end', () => {
			res.end()
		})
	}
})
// 开启服务端口 ↓
server.listen('8080')

// 以上 - node 实现文件流传输就实现好了
======================================
// axios
axios({
 method: 'post',
 url: '/dow',
 data: {},
 headers: {},
 responseType: 'blob', // <= 重点 不写,下载下来的文件会是一个损坏的文件
 onDownloadProgress: (data) => {
	// 进度逻辑
}
});

各种下载方式

var router = function (app) {
  var fs = require("fs");

  app.get("/one", function (req, res) {
    //读取图片
    //第一个参数是下载的资源的url,第二个参数binary(以二进制输出到浏览器,浏览器能自动解析),如果是图片必须设置成binary,否则图片打不开
    // 如果是hex(以16进制输出到浏览器,在浏览器显示的是16进制字符串)
    //第三个参数是回调函数,data是读取的数据
    fs.readFile(
      "/Users/wofu/Desktop/node/temp/1a1f92b4b73412376e2e158bca4021e0",
      "binary",
      function (err, data) {
        if (err) {
          console.log(err);
          return;
        } else {
          res.write(data, "binary"); //图片显示在浏览器上
          //吧图片保存在本地
          //第一个参数是要保存的路径url;第二个是是要保存的数据,第三个参数是以二进制保存,第四个是回调函数
          fs.writeFile(
            "/Users/wofu/Desktop/logonew.png",
            data,
            "binary",
            function (err) {
              if (err) {
                console.log("down fail");
              }
              console.log("down success");
            }
          );

          res.end("");
        }
      }
    );
  });
};

exports.router = router;
====================================
var stream = fs.createReadStream( "/Users/wofu/Desktop/node/temp/1a1f92b4b73412376e2e158bca4021e0" );//参数是图片资源路径
var responseData = [];//存储文件流
if (stream) {//判断状态
    stream.on( 'data', function( chunk ) {
      responseData.push( chunk );
    });
    stream.on( 'end', function() {
       var finalData = Buffer.concat( responseData );
       res.write( finalData );
       //第一个参数是下载下来要存放的位置,第二个参数是图片数据(二进制的),第三个参数必须要binary,第四个是回调函数
       fs.writeFile("/Users/wofu/Desktop/logonew02.png", finalData, "binary", function(err){
             if(err){
                 console.log("下载失败");
             }
             console.log("下载成功");
         });
       res.end();
    });
}
=========================================
var stream = fs.createReadStream( "/Users/wofu/Desktop/node/temp/test.mov" );//参数是图片、视频资源路径
var responseData = [];//存储文件流
if (stream) {//判断状态
    stream.on( 'data', function( chunk ) {
      responseData.push( chunk );
    });
    stream.on( 'end', function() {
       var finalData = Buffer.concat( responseData );
       res.write( finalData.toString("base64")); //传给app,base64 必须要是data二进制类型,一般在实际应用中,app吧图片或视频资源转换成data二进制后base64编码成字符串上传资源给服务器,服务器吧二进制数据解析成视频或图片放到一个目录,建立相应的url放到数据库;app取的时候获取到的是url; 
       //第一个参数是下载下来要存放的位置,第二个参数是图片、视频数据(二进制的),第三个参数必须要binary,第四个是回调函数
       fs.writeFile("/Users/wofu/Desktop/logonew02.mov", finalData, "binary", function(err){
             if(err){
                 console.log("下载失败");
             }
             console.log("下载成功");
         });
       res.end();
    });
}
=================================
    // The must headers.
    res.setHeader('Content-type', 'application/octet-stream');
    res.setHeader('Content-Disposition', 'attachment;filename=aaa.txt');    // 'aaa.txt' can be customized.
    var fileStream = fs.createReadStream('./download/aaa.txt');
    fileStream.on('data', function (data) {
        res.write(data, 'binary');
    });
    fileStream.on('end', function () {
        res.end();
    });
================================================
let _path = path.resolve(__dirname, 'e-router'+'.js')
  let stats=fs.statSync(_path)
  if(stats.isFile()){
    res.set({
      'Content-Type': 'application/octet-stream',
      'Content-Disposition': 'attachment; filename=' + 'e-router'+'.js',
      'Content-Length': stats.size
    });
    fs.createReadStream(_path).pipe(res);
  }else{
    console.log('导出的不是文件!')
  }

文件下载

exports.readFileBySuffixName = function(pathname,fs,request,response){
   var ext = pathname.match(/(\.[^.]+|)$/)[0];//取得后缀名
   switch(ext){    //根据后缀名读取相应的文件,设置响应头,并发送到客户端
       case ".css":
       case ".js":
           //读取文件
           fs.readFile("."+request.url,'utf-8',function(err,data){
               if(err) throw err;
               response.writeHead(200,{  //根据不同的后缀设置不同的响应头
                   "Content-Type":{
                       ".css":"text/css",
                       ".js":"application/javascript",
                   }[ext]
               });
               response.write(data);   //发送文件数据到客户端
               response.end();         //发送完成
           });
           break;
       //jpg、gif、png后缀的图片
       case ".jpg":
       case ".gif":
       case ".png":
           //二进制读取文件
           fs.readFile("."+decodeURI(request.url),'binary',function(err,data){
               if(err)throw err;
               response.writeHead(200,{
                   "Content-Type":{
                       ".jpg":"image/jpeg",
                       ".gif":"image/gif",
                       ".png":"image/png",
                   }[ext]
               });
               response.write(data,'binary'); //发送二进制数据
               response.end();
           });
           break;
       case ".mp4":
           //读取文件的状态
           fs.stat('.'+decodeURI(request.url),function(err,stats){
               if(err){
                   if(err.code === 'ENOENT'){
                       return response.sendStatus(404);
                   }
                   response.end(err);
               }
               //断点续传,获取分段的位置
               var range = request.headers.range;
               if(!range){
                   //206状态码表示客户端通过发送范围请求头Range抓取到了资源的部分数据
                   //416状态码表示所请求的范围无法满足
                   return response.sendStatus(416);
               }
               //替换、切分,请求范围格式为:Content-Range: bytes 0-2000/4932
               var positions = range.replace(/bytes=/,"").split("-");
               //获取客户端请求文件的开始位置
               var start = parseInt(positions[0]);
               //获得文件大小
               var total = stats.size;
               //获取客户端请求文件的结束位置
               var end = positions[1] ? parseInt(positions[1],10):total -1;
               //获取需要读取的文件大小
               var chunksize = (end-start) + 1;

               response.writeHead(206,{
                   "Content-Range":"bytes "+ start+"-"+end+"/"+total,
                   "Accept-Ranges":"bytes",
                   "Content-Length":chunksize,
                   "Content-Type":"video/mp4"
               });
               //创建读取流
               var stream = fs.createReadStream('.'+decodeURI(request.url),{start:start,end:end})
                 .on("open",function(){
                   stream.pipe(response); //读取流向写入流传递数据
               }).on("error",function(err){
                   response.end(err);
               });
           });
           break;
      case ".rar":
         //同步读取文件状态
           var stats = fs.statSync("." + decodeURI(request.url));
               response.writeHead(200,{
                   "Content-Type": "application/octet-stream", //相应该文件应该下载
                   //模板字符串
                   "Content-Disposition": `attachment; filename = ${pathname.replace("/","")}`,
                   "Content-Length":stats.size
               });
            //管道流
            fs.createReadStream("." + decodeURI(request.url)).pipe(response);
            break;
        //以上都不匹配则使用默认的方法
      default:
       fs.readFile('.'+pathname,'utf-8',function(err,data){    
               response.writeHead(200,{
                   "Content-Type":"text/html"
               });
               response.write(data);
               response.end();
           });
       }

页面下载方式
方式一:iframe

const downloadUrl = url => {
  let iframe = document.createElement('iframe');
  iframe.style.display = 'none'
  iframe.src = url
  iframe.onload = function () {
    document.body.removeChild(iframe)
  }
  document.body.appendChild(iframe)
};
module.exports=downloadUrl;

方式二:a标签

let a = document.createElement('a')
a.download = filename
a.href = URL.createObjectURL(blob)
document.body.appendChild(a)
a.click()
URL.revokeObjectURL(blob)
document.body.removeChild(a)
===================================================

function downloadFile (data, fileName) {
  let blob = new Blob([data])
  // 生成a标签
  let downloadElement = document.createElement('a')
  // 创建下载的链接
  let href = window.URL.createObjectURL(blob)
  // a的下载链接
  downloadElement.href = href
  // 设置下载后文件名
  downloadElement.download = fileName
  // 添加a标签
  document.body.appendChild(downloadElement)
  // 点击下载
  downloadElement.click()
  // 下载完成移除元素
  document.body.removeChild(downloadElement)
  // 释放掉blob对象
  window.URL.revokeObjectURL(href)
}
==================================
// 这是传统的下载方式
const downloadFileA = document.createElement('a')
document.body.append(downloadFileA)
downloadFileA.href=`https://xxx`
downloadFileA.download = '下载文件.csv'
// 超链接 target="_blank" 要增加 rel="noopener noreferrer" 来堵住钓鱼安全漏洞。如果你在链接上使用 target="_blank"属性,并且不加上rel="noopener"属性,那么你就让用户暴露在一个非常简单的钓鱼攻击之下。(摘要)
downloadFileA.rel = 'noopener noreferrer'
downloadFileA.click()
document.body.removeChild(downloadFileA)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值