總結我做HTML5檔案上傳外掛程式遇到的技術問題
先貼上原始碼:fileupload-html5.js(PS:公司使用seajs框架)
#問題清單
1. jquery.ajax沒有監聽上傳進度的onprogress事件。
2. XMLHttpRequest(XHR)跨域
問題解答
1. jQuery沒有給出onprogress事件的接口,必須從其他接口中找到原生XHR物件。
jQuery.ajax()回傳的是jqXHR物件。 jqXHR模仿XHR(原生),但沒有模仿實作XHR的所有方法和屬性(如:.upload),即使jqXHR增加了一個特有方法(如:.promise())。所以jqXHR並不是XHR的超集。
//下面是截取jQ內部的源碼,$.ajax();回傳的就是這個jqXHR(偽造XMLHttpRequest)
// Fake xhr jqXHR = { readyState: 0,
#XHR的upload屬性指向XMLHttpRequestUpload(IE10是XMLHttpRequestEventTarget),該物件的onprogress事件可以監聽上傳進度。既然jQ沒有給出這個功能的api,但jQ某些資料上傳方式是使用XHR的,所以我們可以從其它api中找到XHR。在XHR發送資料之前綁定onprogress事件可以實現上傳進度功能。
我從options參數配置中找到兩個與XHR相關的屬性:
- xhr:回呼建立XMLHttpRequest物件。
xhr()回傳值是XHR,提供給jQ使用,也就是傳送資料就是用這個XHR。我們可以透過xhr建立一個回呼函數覆蓋它,同樣傳回XHR,但在此綁定onprogress事件。
//jQ原始碼
// Get a new xhrvar handle, i, xhr = s.xhr();//[回调]在这里,下面是open方法// Open the socket// Passing null username, generates a login popup on Opera (#2865)if ( s.username ) { xhr.open( s.type, s.url, s.async, s.username, s.password );} else { xhr.open( s.type, s.url, s.async );} 所以我们应该这样做: $.ajax({ //..... xhr: function() { var xhr = $.ajaxSettings.xhr(); //绑定上传进度的回调函数 xhr.upload.addEventListener('progress', progress, false); return xhr;//一定要返回,不然jQ没有XHR对象用了 }});
- xhrFields:一對「檔案名稱-檔案值」組成的映射,用於設定原生的 XHR物件。
xhrFields屬性指向jQ內部建立的XHR,我們可以根據xhrFields獲得XMLHttpRequest。由於xhrFields的值只能是json對象,所以不能以下面方式取得。
//錯誤範例
$.ajax({ //...... xhrFields: { upload.onprogress: function() { //语法错误 } } });
我們可以藉助XHR的onsendstart事件,如下:
$.ajax({ //...... xhrFields: { onsendstart: function() { //this是指向XHR this.upload.addEventListener('progress', progress, false); } } });
2. XMLHttpRequestⅡ(XHR)支援跨域,但需要後台允許。
//後台需發送頭部驗證
if($_REQUEST['cros']) { header("Access-Control-Allow-Origin:请求的域名"); }
根據後台給的接口,我需要增加一個參數cros。但我將這個參數與文件同事提交,卻提示跨域限制。最後將這個參數放在url才行。
原來XHR跨域是有兩次請求的,第一次是驗證請求,瀏覽器根據請求目的地址自動發出options請求。若通過,才能發出自訂的post請求。所以將參數放在post請求裡,第一次請求沒有cros參數,也就是不能通過。
以上是HTML5檔案上傳外掛程式遇到的技術問題的詳細內容。更多資訊請關注PHP中文網其他相關文章!