欢迎你们前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~javascript
| 导语 Web技术飞速发展的现在,咱们在感觉新技术带来的便捷和喜悦的同时,也时常在考虑着一个问题:老技术如何迁移。正如本文的主题同样,Flash技术在早年风靡在Web领域,曾经发挥着无尽力量的一个工具正逐渐失去了其重要性。因为性能,兼容性,版权问题,Flash的市场正在消退,曾经靠Flash实现的功能和特性如何完美得进行迁移呢,本文将简单谈一谈Flash的几个常见的特性的替代方案。html
咱们知道Flash能够播放.swf文件的动画视频,并且具备很强的控制功能,之前不少Web视频播放器都是基于Flash去实现的。包括embed标签,都是如此。全部视频源为swf的文件的视频都须要借助Flash去播放。前端
在移动端设备上,使用HTML5的video标签基本没有问题。 在PC上,IE低版本(IE8-)浏览器上除了Flash目前没有其它办法 在PC上,IE9+和其它如今浏览器,采用HTML5标签。 综合来讲,能够统一用如下一段代码实现兼容:html5
<video width="400" height="300" controld> <!-- mp4格式适用于IE9+,Chrome,Safari --> <source src="test.mp4" type="video/mp4"></source> <!-- ogg格式适用于FireFox,Opera,Chrome --> <source src="test.ogg" type="video/ogg"></source> <!-- webm格式适用于FireFox,Opera,Chrome --> <source src="test.webm" type="video/webm"></source> <!-- object须要Flash支持,当IE8-时考虑 --> <object data="test.mp4" width="400" height="300"> <!-- embed须要Flash支持,当IE8-时考虑 --> <embed src="test.swf" width="400" height="300"> </object> </video>
目前在PC端a.qq.com的页面请求b.qq.com的一个接口是理论上跨域的一个请求,旧版本浏览器特别是只支持XMLHTTPRequest Level1的浏览器,须要访问跨域请求,要么使用jsonp,要么只能使用Flash。 使用Flash进行跨域须要作的事情是java
1.a.qq.com的js与Flash交互 2.Flash校验安全性,检查b.qq.com下根目录的crossDomain.xml文件的控制访问属性 3.Flash做为中间代理请求b.qq.com 4.Flash将请求结果返回给a.qq.com的js 图1简明扼要的描述了这个过程。jquery
图1 Flash跨域请求web
条件:要使用CORS,必须在支持XmlHttpRequest Level2的浏览器中(IE10+和其它现代浏览器) 作法:设置withCredentials头,而后结合后台设置的Access-Control-Allow-Origin头进行控制,进行跨域便可。相关代码以下: 前端JS:ajax
$.ajax({ url:"http://b.qq.com/api/xxx.php", type:"POST", xhrFields:{ withCredentials:true }, success:function(){ //... }, fail:function(){ //... } })
后端PHP:json
<?php //b.qq.com的接口中添加Access-Control-Allow-Origin头 header("Access-Control-Allow-Origin:http://a.qq.com");
咱们回到同源策略,若是要请求b.qq.com下的一个接口,咱们从b.qq.com下的页面发起请求,是遵循同源策略的。那么咱们能够在接口域名下放一个统一的html文件,用于代理咱们请求b.qq.com的接口,而后将结果告诉a.qq.com就能够了。 这种状况下要解决2个主要问题: 1.cookie如何发送 2.a.qq.com与b.qq.com的代理页面前端通讯 其实两个问题是一个问题,a.qq.com下的cookie咱们是能够获取到的,一样的cookie咱们能够种在b.qq.com下的。问题归结到第二个问题,如何在前端实现a.qq.com和b.qq.com两个页面之间的通讯。 有两个方法:
主要核心逻辑代码能够参考: 【a.qq.com页面代码】
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> </head> <body> <script> //a.qq.com中逻辑: var $proxyFrame=$("<iframe style='display:none' src='http://b.qq.com/proxy.html'></iframe>").appendTo(document.body); //等待iframe中转页面load完毕 $proxyFrame.on("load",function(){ //调中转页面 $proxyFrame.get(0).contentWindow.postMessage({ api:"/xx/y", data:{ a:1, b:2 }, cookie:document.cookie//带过去的cookie }); //回调 $(window).on("message",function(e){ var event=e.originalEvent; if(event.origin=="http://b.qq.com"){ console.log("response data:",event.data); } }) }) </script> </body> </html>
【b.qq.com页面代码】
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> </head> <body> <script> //b.qq.com中逻辑: $(window).on("message",function(e){ var event=e.originalEvent; if(event.origin=="http://a.qq.com"){ var api=event.data.api; var data=event.data.data; var cookie=event.data.cookie; //种植cookie //.........种植cookie的操做 //代理请求接口 $.ajax({ url:api, data:data, //....... success:function(result){ //将response返回给a.qq.com window.parent.postMessage(result,"*") }, fail:function(){ } }) } }) </script> </body> </html>
以上demo简单解决了前端跨域通讯,跨域带cookie等问题,在逻辑上彻底能够实现跨域通讯。可是对于不支持PostMessage特性的老版浏览器是行不通的。好比IE8-浏览器就不能很好的支持PostMessage特性。这种状况下咱们采用另一种中转跨域的方案:降子域通讯。 下面介绍第二种方法:降子域通讯:
因为a.qq.com和b.qq.com都是属于qq.com下的子域,同源策略在前端页面中断定依据是document.domain而不是location.host。而document.domain可写,能够人为更改到其父域名。这样a.qq.com和b.qq.com的两个页面均可以自行降到qq.com。这样就能够直接进行通讯。 主要核心逻辑代码能够参考: 【a.qq.com页面代码】
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> </head> <body> <script> //a.qq.com中逻辑: document.domain="qq.com"; var $crossFrame=$("<iframe style='display:none' src='http://b.qq.com/proxy.html'></iframe>").appendTo(document.body); //等待iframe中转页面load完毕 $crossFrame.on("load",function(){ //回调 window['callback']=function(result){ //收到响应 console.log("receive response:",result); } //调中转页面中的方法直接请求 $crossFrame.get(0).contentWindow.request({ api:"/xx/y", data:{ a:1, b:2 } }); }) </script> </body> </html>
【b.qq.com页面代码】
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> </head> <body> <script> //b.qq.com中逻辑: document.domain="qq.com"; window.request=function(api,data){ $.ajax({ url:api, data:data, //....... success:function(result){ //将response返回给a.qq.com window.parent.callback(result,"*") }, fail:function(){ } }) } </script> </body> </html>
在实际改造过程当中,若是后端结果过多,或者改造不方便,能够直接采用第二种方式——中转代理的方式进行改造。其原理示意图总结以下:
图2 去Flash跨域请求改造指导图
其实文件上传是HTML规范内的,理论上不须要使用Flash去作。可是随着ajax技术的兴起,Web 2.0时代的到来,input表单的提交改为ajax提交,页面无刷新的形式。可是这种形式下对于文件这类二进制文件没法提交,IE下原本有ActiveX 的FSO能够操做,可是插件的执行须要IE安全机制容许,不少状况下用户体验很差,并且兼容性也不是很好。因而这种背景下,FLash又担当起了一个新的功能:文件上传。 著名的jquery插件,ajaxupload.js就是用的Flash进行文件提交。
如何不使用Flash,上传文件,并且保证页面不刷新,是咱们在去Flash上传工做中须要作的核心。下面针对不一样的浏览器提供两套方案:
条件:支持HTML5 FileReader 和FormData 特性 作法:
1.获取input表单的files对象 2.实例化FileReader对象,并解析files对象 3.解析以后输出base64编码的文件数据 4.base64的数据传入FormData 5.ajax提交FormData
参考demo以下:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> </head> <body> <input type="file" name="test" id="test" /> <script> $("#test").change(function(e){ var files=e.target.files; va fr=new FileReader(); fr.onload=function(e){ var fm=new FormData(); fm.append("file_test",e.target.result); //额外参数 fm.append("sExtend","test"); //提交ajax $.ajax({ url:'http://b.qq.com/cgi/', type:"POST", dataType:json, data:fm, processData: false, // 不会将 data 参数序列化字符串 contentType: false, // 根据表单 input 提交的数据使用其默认的 contentType success:function(result){ console.log(result); }, fail:function(){ console.log("failed"); } }); } fr.readAsDataURL(files[0]); }); </script> </body> </html>
条件:无任何条件,支持任何浏览器 作法:
1.在页面上构建一个隐藏的iframe 2.在页面上构建一个form表单,表单中包含文件表单和其它附加字段表单,target设为上述iframe的id 3.上传文件动做触发时,调用form的submit方法 4.iframe中加载上传cgi,返回结果与父窗口通讯,若是iframe与cgi跨域,则参考【第二部分:跨域请求】进行处理
参考demo以下:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>DEMO-上传文件</title> </head> <body> <!-- 以a.qq.com上传到b.qq.com/upload/为例 --> <form action="http://b.qq.com/upload/" enctype="multipart/form-data" method="post" target="postframe" name="fileform"> <!-- 文件上传按钮 --> <input type="file" name="file_1" /> <!-- 隐藏的附加字段 --> <input type="hidden" name="sExtend1" value="test1" /> <input type="hidden" name="sExtend2" value="test2" /> </form> <iframe src="" frameborder="0" style="display:none;" id="postframe"></iframe> <script> //监听文件基本信息 $("[name=file_1]").change(function(e){ var files=e.target.files; if("undefined" == typeof files && e.target.value){ //IE9- files=[]; try{ files=[new ActiveXObject("Scripting.FileSystemObject").GetFile(e.target.value)]; }catch(err){ files=[{ name:e.target.value, type:"unkown" }]; } if(!files.length){ files=[{ name:e.target.value, type:"unkown" }]; } } //获取文件信息 console.log(files); }) //上传 $("[name=fileform]").submit(); //回调 window.fileCallback=function(result){ //处理result console.log("文件上传成功"); } </script> </body> </html>
总结
本文给出了笔者在实际工做中遇到的最多见的去Flash改造的三种场景,现以表格的形式简单归纳以下:
现代H5 | 早期低版本IE等 | |
---|---|---|
视频播放 | 使用H5的video标签 | 没办法只能使用FLash,若是不用Flash,建议提醒用户升级浏览器 |
跨域提交请求 | 使用CORS,先后端结合 | 中转代理(PostMessage或者降域) |
Ajax文件上传 | 使用FileReader+FormData封装 | 模拟表单提交到iframe |
结语
去Flash不只是对实现方案的一种兼容改造,更是对早已成熟的新技术新思路的运用。目前而言,不论是由于政策缘由,仍是由于性能或者其它兼容性缘由,去Flash改造都是重要和紧迫的,本文是笔者在实际工做过程当中总结出的最多见的三种去Flash场景和改造方案,供参考,不足之处还请不吝指正。
相关阅读
再论 ASP.NET 中获取客户端IP地址
从零开始的Spring Session
【每日课程推荐】机器学习实战!快速入门在线广告业务及CTR相应知识
此文已由做者受权腾讯云+社区发布,更多原文请点击
搜索关注公众号「云加社区」,第一时间获取技术干货,关注后回复1024 送你一份技术课程大礼包!
海量技术实践经验,尽在云加社区!