前端学习随记の下载上传篇 —— 下载篇

前端学习随记の下载上传篇 —— 下载篇

闲言: 懒懒懒!!!好长时间不写文章了,一直出差魔都,学习一些其他知识开发项目,也时不时的空闲时间深度学习一些前端基础知识。好吧,不找理由,就是懒哇哈哈(✿◡‿◡)。

demo代码:https://github.com/NARUTOne/DownAndUp.git

参考传送门:
http://www.cnblogs.com/voiphudong/p/3284724.html
https://scarletsky.github.io/2016/07/03/download-file-using-javascript/#参考资料
https://developer.mozilla.org/zh-CN/docs/Web/API/FileSystem

引言###

上传下载一直是项目上非常常见的需求,也是对于我这种前端小白来说一直隐隐犯怵的地方,不太熟悉,加上项目上用过一次,同事朋友也问过遇到过,所以打算好好恶补这块↖(ω)↗。本篇先说下下载,上传留着下篇来说,欢迎关注留bug.

几种下载方式

前后端下载方式原理简述:

1)标准URL下载方式: 可以通过在web页面中嵌入 url超级链接,标准的HTTP GET请求。对于服务器端web根目录有一个test.zip的文件。此种方法的弊端是完全暴露了文件test.zip的网站路径,而且动态性不够灵活。

2)通过服务器端脚本向浏览器方(stdout)输出二进制流的方式下载: 上述方法可以在服务器端 通过 脚本程序 download.php ,并且根据传入的查询字符串f=test.zip定位服务器上文件系统test.zip的路径,然后按二进制流的方式发送给客户端浏览器,那么客户端浏览器就会弹出一个“下载对话框”了。

form 表单下载

POST的URL下载链接,可以通过设置form表单的action 以及 表单元素值来完成下载。

function downLoad () {
  var form = document.createElement('form');   //定义一个form表单
  form.style = 'display:none';   //下面为在form表单中添加查询参数
  form.target = '';
  form.method = 'post';
  form.action = url;//下载接口

  var input1 = document.createElement('input');
  input1.type = 'hidden';
  Input1.name = 'exportData';
  input1.value = (new Date()).getMilliseconds(); 

  document.body.appendChild(form)  //将表单放置在web中
  form.appendChild(input1);   //将查询参数控件提交到表单上
  form.submit();   //表单提交
}

iframe

iframe有一个src属性,其本质就是发送http请求,GET一个页面或者数据,可以通过一个动态生成的隐藏的iframe来得到下载的二进制文件。

function download(){
  var IFrameRequest=document.createElement("iframe");
  IFrameRequest.id="IFrameRequest";
  IFrameRequest.src="/test.zip";
  IFrameRequest.style.display="none";
  document.body.appendChild(IFrameRequest);
}

HTML5のdownload属性

由于浏览器的安全策略的限制,我们通常只能通过一个额外的页面,访问某个文件的 url 来实现下载功能,但是这种用户体验非常不好。HTML 5 里面为 a 标签添加了一个 download 的属性,我们可以轻易的利用它来实现下载功能。

<a href="http://somehost/somefile.zip" download="filename.zip">Download file</a>

a标签添加 download 属性,我们点击这个链接的时候就会自动下载文件了~
顺便说下,download 的属性值是可选的,它用来指定下载文件的文件名。像上面的例子中,我们下载到本地的文件名就会是 filename.zip 拉,如果不指定的话,它就会是 somefile.zip 这个名字啦!

当然,我们还可以动态创建a标签实现下载:

function download() {
  var a = document.createElement('a');
  var url = window.URL.createObjectURL(blob);
  var filename = 'what-you-want.txt';
  a.href = url;
  a.download = filename;
  a.click();
  window.URL.revokeObjectURL(url);
}

window.URL 里面有两个方法:
createObjectURL 用 blob 对象来创建一个 object URL(它是一个 DOMString),我们可以用这个 object URL 来表示某个 blob 对象,这个 object URL 可以用在 href 和 src 之类的属性上。
revokeObjectURL 释放由 createObjectURL 创建的 object URL,当该 object URL 不需要的时候,我们要主动调用这个方法来获取最佳性能和内存使用。
当然,如果你没有blob对象的url,也可以不用window.URL,直接使用下载地址url。

HTML5のFileSystem

由于这种方法目前大多数浏览器不支持,仅仅chrome支持,具体方式可以查看大神们的文章,我就不搬运了。(✿◡‿◡)
https://imququ.com/post/a-downloader-with-filesystem-api.html

其他方式

Window.open(url):这种方式在目前的网络环境及安全限制下被拦截已经不太好使了,主要用来是打开新窗口下载。

var new_window = null;
function downLoad () {
  var isSure=confirm("是否下载")
  if (isSure){
    new_window = window.open()
    new_window.location.href = 'https://github.com/WZOnePiece/study-draggable/archive/master.zip';
    document.getElementById('result').innerHTML = "You downLoad OK!"
  }
  else{
    document.getElementById('result').innerHTML = "You pressed Cancel!"
  }
}
function closeDownLoad() {
  new_window  && new_window.close();
}

//使用a链接target='_blank',则不会拦截下载
function AdownLoad() {
  var url = 'https://github.com/WZOnePiece/study-draggable/archive/master.zip';
  var a = document.createElement("a");
  a.setAttribute("href", url);
  a.setAttribute("target", "_blank");
  a.setAttribute("id", "camnpr");
  document.body.appendChild(a);
  a.click();
}

这里主要是用window.open 打开窗口,接着使用location.href = url进行重定向避免拦截进行下载。

补充知识

Blob 对象

Blob 全称是 Binary large object,它表示一个类文件对象,可以用它来表示一个文件。根据 MDN 上面的说法,File API 也是基于 blob 来实现的。

构建 blob 的方式就是通过服务器返回的文件来创建 blob ,采用File API及Fetch API。

fetch('http://somehost/somefile.zip').then(res => res.blob().then(blob => {
  var a = document.createElement('a');
  var url = window.URL.createObjectURL(blob);
  var filename = 'myfile.zip';
  a.href = url;
  a.download = filename;
  a.click();
  window.URL.revokeObjectURL(url);
}))

注意:Fetch API 目前浏览器支持不好,详情看https://developer.mozilla.org/zh-CN/docs/Web/API/Fetch_API/Using_Fetch
File API的详细介绍:https://developer.mozilla.org/zh-CN/docs/Using_files_from_web_applications
可以利用fetch配合reader对象来实现进度条功能

限制

1、不同浏览器对 blob 对象有不同的限制

Supported browsers

Browser Constructs as Filenames Max Blob Size Dependencies
Firefox 20+ Blob Yes 800 MiB None
Firefox < 20 data: URI No n/a Blob.js
Chrome Blob Yes [500 MiB][3] None
Chrome for Android Blob Yes [500 MiB][3] None
Edge Blob Yes ? None
IE 10+ Blob Yes 600 MiB None
Opera 15+ Blob Yes 500 MiB None
Opera < 15 data: URI No n/a Blob.js
Safari 6.1+* Blob No ? None
Safari < 6 data: URI No n/a Blob.js

2、构建完 blob 对象后才会转换成文件。

文件大点的话,要等到下载完文件之后才能构建 blob 对象,再转化成文件,页面显示上不太友好,没有提示。这时建议采用a标签,防止用户的错误认知造成重复点击下载,资源浪费。

服务器出错

  • 1、window.open(url)

打开一个带错误信息的页面

  • 2、window.location.href

页面将跳转到一个错误页面

  • 3、iframe

用户感知不到任何变化

  • 4、a标签

直接出现 下载失败

当然,如果response header里有content-disposition字段的话,浏览器都会下载一个带错误信息的文件。这时候,其实我们可以多发一个ajax/fetch请求,先检测下接口状态,然后再取做下载逻辑。但这样就对服务器造成了额外的开销。

这样的体验都不太好,作为一个追求极致体验的程序猿,我们应该重新思考下,如何提升用户体验。

结语##

O(∩_∩)O,这篇下载篇就这样简单介绍下,至于还有其他的方式,欢迎留言告知;代码及描述上有bug也希望不吝指出。谢谢哈!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 221,820评论 6 515
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,648评论 3 399
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 168,324评论 0 360
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,714评论 1 297
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,724评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,328评论 1 310
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,897评论 3 421
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,804评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,345评论 1 318
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,431评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,561评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,238评论 5 350
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,928评论 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,417评论 0 24
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,528评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,983评论 3 376
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,573评论 2 359

推荐阅读更多精彩内容