Open abbshr opened 9 years ago
web标准发展至今,浏览器能干的事越来越多了,各种新鲜技术的出现无疑扩展了客户端app的职能,比如说上一篇po提到的ArrayBuffer、Blob、URL等。这个寒假我写了一個文件拖拽上传的脚本。当时我想毕竟这是一个正经的web应用,就算是前端也一定要做到尽量无可挑剔。因此,新鲜技术终于得以利用。
ArrayBuffer
Blob
URL
我们暂且不考虑应用架构和代码风格,怎么做才能无可挑剔呢?答案就是把严格控制工作流程的每一环节:从选择文件到解析文件再到文件上传最后到善后工作。(当然,如果人家禁用JavaScript所有的工作都前功尽弃了。不过为了弥补这一不足,我们在后面会有一个小小的解决方案。)
文件的获取有两个途径:A.上传按钮选择; B.拖拽选择。这没啥可说的,只是为了方便拖放操作额外写了一个拖放事件库,代码就不贴了。
关键是文件解析。或许你要问“上传个文件给服务器,为毛在前端弄那么复杂?”,还是那句话“为了做到应用的完整与无可挑剔”。上传时我们考虑之允许指定格式的文件,如“PDF、DOC、JPEG、CAD”等等能形成人类可读文档的文件,如果文件格式不满足要求则拒绝上传。
要想检测文件类型,至少得把文件头读出来。怎么做?要是以前还真就麻烦了,可是现在web标准给出了FileReader,使用它可以将二进制的blob文件进行转化处理。还记得ArrayBuffer吗?这里我们就用他们来完成文件头的获取:
FileReader
var typeVerify = function (file) { var filereader; var token = true; // 创建一个FileReader filereader = new FileReader(); filereader.onload = verify; // 以异步方式将file转成ArrayBuffer(同步方式只有在Worker线程中才可用) filereader.readAsArrayBuffer(file.slice(0, 4)); function verify(e) { var buffer = e.target.result; // 创建一个DataView对象用来按字节处理结果 var dataView = new DataView(buffer); // false以大端次序读取2字节(true为小端次序) var fh = dataView.getUint16(0, false); // 如果得到的值不在fileHeader里 if (fileHeader.indexOf(fh) == -1) token = false; return token; } };
OK,我们已经把过程封装到函数,用来检测来自用户输入的文件是否满足要求。
WebSocket、Ajax可供选择,鉴于长连接开销问题,选择Ajax吧。新的XMLHttpRequest 2标准中规定了用于文件上传的接口,可用于二进制文件上传以及监测文件上传进度等。
var asyncUpload = function (binfile) { var xhr = new XMLHttpRequest(); // 注册该事件可用于获取上传进度 xhr.upload.onprogress = updateProcess; // 上传成功 xhr.upload.onload = success; // 上传结束(无论成败) xhr.upload.onloadend = end; xhr.upload.onerror = error; // 服务器返回结果 xhr.onreadystatechange = watchState; xhr.open('POST', '/upload'); // 设置响应类型 xhr.responseType = 'blob'; xhr.send(binfile); };
大体的架构设计算结束了,最后一步是什么呢?
对了,我们折腾了半天,要是用户不买账,把JavaScript给禁用了或给你改了咋办???……
这个做法着实让人气愤,为了防止自己的成果功亏一亏,我考虑了这种办法:
Header
不过呢,尽管是这样做,还是有很多漏洞的,仅仅能打消一下hacking的念头,如果用户真的想整整你,办法还是多的去的。
web标准发展至今,浏览器能干的事越来越多了,各种新鲜技术的出现无疑扩展了客户端app的职能,比如说上一篇po提到的
ArrayBuffer
、Blob
、URL
等。这个寒假我写了一個文件拖拽上传的脚本。当时我想毕竟这是一个正经的web应用,就算是前端也一定要做到尽量无可挑剔。因此,新鲜技术终于得以利用。我们暂且不考虑应用架构和代码风格,怎么做才能无可挑剔呢?答案就是把严格控制工作流程的每一环节:从选择文件到解析文件再到文件上传最后到善后工作。(当然,如果人家禁用JavaScript所有的工作都前功尽弃了。不过为了弥补这一不足,我们在后面会有一个小小的解决方案。)
获取文件
文件的获取有两个途径:A.上传按钮选择; B.拖拽选择。这没啥可说的,只是为了方便拖放操作额外写了一个拖放事件库,代码就不贴了。
类型检测
关键是文件解析。或许你要问“上传个文件给服务器,为毛在前端弄那么复杂?”,还是那句话“为了做到应用的完整与无可挑剔”。上传时我们考虑之允许指定格式的文件,如“PDF、DOC、JPEG、CAD”等等能形成人类可读文档的文件,如果文件格式不满足要求则拒绝上传。
要想检测文件类型,至少得把文件头读出来。怎么做?要是以前还真就麻烦了,可是现在web标准给出了
FileReader
,使用它可以将二进制的blob文件进行转化处理。还记得ArrayBuffer
吗?这里我们就用他们来完成文件头的获取:OK,我们已经把过程封装到函数,用来检测来自用户输入的文件是否满足要求。
异步上传
WebSocket、Ajax可供选择,鉴于长连接开销问题,选择Ajax吧。新的XMLHttpRequest 2标准中规定了用于文件上传的接口,可用于二进制文件上传以及监测文件上传进度等。
最后一步
大体的架构设计算结束了,最后一步是什么呢?
对了,我们折腾了半天,要是用户不买账,把JavaScript给禁用了或给你改了咋办???……
这个做法着实让人气愤,为了防止自己的成果功亏一亏,我考虑了这种办法:
Header
,通常web浏览器最差也得通过表单实现上传,表单上传的缺点之一是没法控制请求头。那么我们就用ajax添加个特殊的请求头。不过呢,尽管是这样做,还是有很多漏洞的,仅仅能打消一下hacking的念头,如果用户真的想整整你,办法还是多的去的。