歡迎你們前往騰訊雲+社區,獲取更多騰訊海量技術實踐乾貨哦~javascript
| 導語 Web技術飛速發展的現在,咱們在感覺新技術帶來的便捷和喜悅的同時,也時常在考慮着一個問題:老技術如何遷移。正如本文的主題同樣,Flash技術在早年風靡在Web領域,曾經發揮着無盡力量的一個工具正逐漸失去了其重要性。因爲性能,兼容性,版權問題,Flash的市場正在消退,曾經靠Flash實現的功能和特性如何完美得進行遷移呢,本文將簡單談一談Flash的幾個常見的特性的替代方案。html
咱們知道Flash能夠播放.swf文件的動畫視頻,並且具備很強的控制功能,之前不少Web視頻播放器都是基於Flash去實現的。包括embed標籤,都是如此。全部視頻源爲swf的文件的視頻都須要藉助Flash去播放。前端
在移動端設備上,使用HTML5的video標籤基本沒有問題。 在PC上,IE低版本(IE8-)瀏覽器上除了Flash目前沒有其它辦法 在PC上,IE9+和其它如今瀏覽器,採用HTML5標籤。 綜合來講,能夠統一用如下一段代碼實現兼容:java
<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進行跨域須要作的事情是jquery
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簡明扼要的描述了這個過程。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> 複製代碼
在實際改造過程當中,若是後端結果過多,或者改造不方便,能夠直接採用第二種方式——中轉代理的方式進行改造。其原理示意圖總結以下:
其實文件上傳是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場景和改造方案,供參考,不足之處還請不吝指正。
相關閱讀
此文已由做者受權騰訊雲+社區發佈,更多原文請點擊
搜索關注公衆號「雲加社區」,第一時間獲取技術乾貨,關注後回覆1024 送你一份技術課程大禮包!
海量技術實踐經驗,盡在雲加社區!