前端文件下载的方式

更新日期: 2019-04-13阅读: 4.5k标签: 文件

Content-Disposition / Content-Type

Content-Disposition

http 头部的 Content-Disposition字段,规定了返回的内容用什么形式展示

value含义是否默认
inline以网页或者页面的一部分
attachment以附件的形式下载并保存到本地
http.createServer((req, res) => {
  res.setHeader("Content-Disposition", "attachment")
  res.end('123 - 321 - 1234567')    
})

前端需要使用window.open 形式访问 此路由就可以实现文件的下载

window.open(xxxx)

或者使用 H5新属性 a 标签

<a type='download' href=xxx> 点击下载 </a>


Content-Type

http.createServer((req, res) => {
  res.setHeader("Content-Type", "application/octet-stream")
  res.end('123 - 321 - 1234567')    
})

同上前端使用 open 或者 a标签进行处理

备注: 如果使用普通的请求,是不可以的,比如使用ajax


window.open

window.open 可以下载文件的原因是,浏览器遇到无法解析的文件就是执行下载

当使用浏览器打开文件时, 如果它无法解析,那么就会把该文件下载下来

http.createServer((req, res) => {
  const data = fs.readFileSync('./Zip.zip')
  res.end(data)    
})

拿到的data是一个buffer 对象,那么直接写一个Buffer可以实现下载么

data = new Buffer('我是谁,谁是我')

尝试后发现,koa是可以的。但是原生直接这么写是不行的

http.createServer((req, res) => {
  const newBuf = new Buffer('我是谁,谁是我')
  res.end(newBuf)    
})


通过接口拿到数据之后进行下载

在实际项目中,文件下载可能出现的场景

  • 对于已经在服务器存在的文件进行下载,比如图片资源
  • 将一些查询数据导出到本地, 比如mysql查询结果导出csv

对于已存在的资源,可以直接使用 上面说的 winodw.open 或者 a 标签进行下载,那么对于不是以文件形式存在的资源呢


data URI

经常见到使用 data URI scheme 的是图片, 一般为了减少http请求,会将图片直接以base64的形式展示在html

<img src='data:image/png;base64,xxxxxx'/>

也可以应用到文件下载中

router.get('/download', async (ctx, next) => {
  const newBUf = new Buffer('我是谁,谁是我')
  ctx.body = newBUf
}
axios.get(`${path}`)
.then(function ({data}) {
  let a = document.createElement('a');
  a.href = "data:text/plain;charset=utf-8," + data;
  a.download = "myfilename.png";
  a.click();
// 记得处理临时元素 防止内存泄漏
  a = null
})


Blob

Blob 是表示一个类文件对象,可以用它来表示一个文件

server 部分

http.createServer((req, res) => {
  res.setHeader("Access-Control-Allow-Origin", "*");
  let end = ''
  if (req.url.includes("/down")) {
    const newBUf = new Buffer('我是谁,谁是我')
    end = newBUf
  }
  res.end(end)
}  

前端

const xhr = new XMLHttpRequest();
xhr.open('GET', path);
xhr.responseType = 'blob';

xhr.onload = function() {
	const blob = xhr.response;
	const url = URL.createObjectURL(blob);
	// 通过a标签去下载
	const link = document.createElement('a');
	link.href = url;
	link.download = fileName;
	link.click();
	link = null

	URL.revokeObjectURL(url);
};
xhr.send();

尝试用 window.open 方式,发现不可以

目前常用的各个第三方库也支持返回内容为blob格式

  axios.get(`${path}`, {
    responseType: 'blob'
  })

或者 fetch

fetch(path).then(res => res.blob().then(blob =>{ ... })


window.URL

  • createObjectURL

    用 blob 对象来创建一个 object URL(它是一个 domString),我们可以用这个 object URL 来表示某个 blob 对象,这个 object URL 可以用在 a 标签的 href属性上,然后触发点击事件,就可以下载文件了

  • revokeObjectURL

    为了避免避免内存泄漏,需要手动释放创建的 object URL

缺点

  • 构建完 blob 对象后才会转换成文件

代码就能看出,需要先将返回内容转为blob才进行下载操作,如果用户操作的是一个很大的资源,在等待文件正式下载前,还需要一段时间等待格式的转化


实例

将mysql数据 导出 csv

这边直接用数据模拟mysql查询结果, 在网上查到两种拼接方式,肯定有其余的方案

第一种

const result = [
  ['id', 'oreder', 'name', 'status' ],
  [1, '201904120201', '正在加载', '已完成'],
  [18, '201904120204', '测试189', '待付款'],
  [22, '201904120209', '蓝田日暖', '待付款'],
]

// 可以看到 result 数组的第一组是 csv的各个字段标题 

const data = csvData.reduce((cur, next) => `${cur + next.join(',')}\n`, '')
const blob = new Blob([data]);
const url = URL.createObjectURL(blob);
let a = document.createElement('a');
a.href = url;
a.download = filename;
a.click();
a = null

window.URL.revokeObjectURL(url);

第二种

const result = [
  [1, '201904120201', '正在加载', '已完成'],
  [18, '201904120204', '测试189', '待付款'],
  [22, '201904120209', '蓝田日暖', '待付款'],
]

// result 就是正常的数据格式

  // 解决乱码问题
  let dataType = '\uFEFF'
  // 添加表格的头子段
  dataType += (['  订单编号', '用户', '动态ID'].join(',')) 
  dataType += '\n'

  csvData.forEach(item => { 
    dataType += ([item.id, item.order, item.name, item.staus].join(','))
    dataType += '\n'
  })

  const blob = new Blob([dataType], {type: 'text/csv'})    


如果有几段流文件,前端需要下载拼接成一个完整文件,如何实现

肯定是在 server端进行文件的拼接操作,然后返回到前端下载

大致过程

const content1 = '这里是第1段文件内容'

const content2 = '这里是第2段文件内容'

ctx.body = { code:200, data: content1 + content2 }

前端就是上文中的blob 下载方式了

批量下载如何处理

其实这个问题是在查询资料的过程有人提到的问题

window.open

批量写了多个 window.open 在Chrome中 可以正常使用,但是在safari中,只能打开一个窗口,下载一个文件

转为下载一个zip 文件

感觉如果将所有文件合并成为一个xxx.zip 然后对 这个zip文件做下载。不过这种方式有问题,目前查到的大部分过程都是会在服务器新建出一个 zip 文件,等下载完毕在做删除,还没有找到可以跨过这一步的方式。


链接: https://www.fly63.com/article/detial/2854

h5移动端实现图片文件上传

PC端上传文件多半用插件,引入flash都没关系,但是移动端要是还用各种冗余的插件估计得被喷死,项目里面需要做图片上传的功能,既然H5已经有相关的接口且兼容性良好,当然优先考虑用H5来实现。

前端使用js读取文件操作

首先我们定义一个input标签type=file、然后我们定义一个jsReadFiles的方法将文件作为参数;当上传文件的时候读取这个文件。图片上传成功,只是图片路径变成了base64编码的形式。

HTML5实现文件读取、编辑、保存

HTML5读取文件主要利用的就是FileReader这个API,它的使用需要从一个构造函数开始,保存文件的关键是生成文件对象,可以使用URL.createObjectURL()方法实现,该方法能返回给定对象的URL,用在<a>标签的href属性上就可以创建可下载的文件链接。

血淋淋的事实告诉你:你为什么不应该在JS文件中保存敏感信息

在JavaScript文件中存储敏感数据,不仅是一种错误的实践方式,而且还是一种非常危险的行为,长期以来大家都知道这一点。

在js文件中引入另一个js文件的实现方法总汇

比如我写了一个JS文件,这个文件需要调用另外一个JS文件,该如何实现呢?这篇文章主要介绍:在js文件中引入另一个js文件的实现

使用HTML5来实现本地文件读取和写入

最近有这样一个需求,就是在HTML页面中有个按钮导出,点击它,将构造一个文档并存储到本地文件系统中。另外还有个按钮,点击它,从本地文件系统中读取一个文件并对内容进行分析。

lock文件_我们为什么需要 lock 文件

从 Yarn 横空出世推出 lock 文件以来,已经两年多时间了,npm 也在 5.0 版本加入了类似的功能,lock 文件越来越被开发者们接收和认可。本篇文章想从前端视角探讨一下我们为什么需要 lock 文件,以及它的一些成本与风险,当然其中一些观点对于后端也是适用的

什么是断点续传?前端如何实现文件的断点续传

什么是断点续传?就是下载文件时,不必重头开始下载,而是从指定的位置继续下载,这样的功能就叫做断点续传。前端通过FileList对象获取到相应的文件,按照指定的分割方式将大文件分段,然后一段一段地传给后端,后端再按顺序一段段将文件进行拼接。

form表单文件上传_multipart/form-data文件上传

form表单的enctype属性:规定了form表单数据在发送到服务器时候的编码方式.。application/x-www-form-urlencoded:默认编码方式,multipart/form-data:指定传输数据为二进制数据,例如图片、mp3、文件,text/plain:纯文本的传输。空格转换为“+”,但不支持特殊字符编码。

使用HttpClient发送文件流到服务器端

适用场景: 网络绝对路径的URL文件或图片,不存储到本地,转换成stream,直接使用HTTPClient传送到SpringBoot的服务端,将文件存储下来,并返回一个文件地址。目前分层架构的系统越来越多这种需求,所以记录下来以备不时之需。

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!