天天看點

ajax 請求二進制流 圖檔 檔案 XMLHttpRequest 請求并處理二進制流資料 之最佳實踐

本文轉自一位高人的部落格:情郎 Blog

寫在前面 :從提出需求到完美的解決問題,實作過程是曲折的。

需求:在前(web client)後(Restful Service)端完全解耦的模式架構下,webclient需要請求 Service 傳回的圖檔檔案(二進制流),并在client端顯示。

第一步思考:拿到此需求, 基于程式員的狂妄心裡,思考到顯示圖檔而已,jquery ajax直接get請求 将傳回data 指派給img标簽的src屬性即可嘛,so easy~

不知天高地後的小子開始碼代碼,經過幾分鐘給出了以下的代碼,并自信滿滿的準備測試。

$.ajax({
    method: "GET",
    url: serverUrlBase + "/server/images/" + mapid + "/files/png",//跨域,請求會傳回流檔案 png圖檔
    beforeSend: function (xhr) {
        xhr.setRequestHeader("client_type", "DESKTOP_WEB");
        xhr.setRequestHeader("desktop_web_access_key", _desktop_web_access_key);
    },
    success: function (data) {
        $("#remoteimg").attr("url", data);
    }
});
           

在visual studio 中選中檔案 在浏覽器中檢視。

ajax 請求二進制流 圖檔 檔案 XMLHttpRequest 請求并處理二進制流資料 之最佳實踐

這是個什麼~!!!!!!!!!!!!!!! 不符合期望啊~~~ !!!!!!!!!

第二步思考:後端那小子給的API肯定有問題。先用工具測試看看。

ajax 請求二進制流 圖檔 檔案 XMLHttpRequest 請求并處理二進制流資料 之最佳實踐

打開chorme ,打開裝好的postman元件,輸入請求位址,點選SEND。等待兩秒鐘一副超大的圖檔檔案顯示出來了~~

第三步思考:後端那小子的接口是正常的。 問題在我自己身上(表情漸漸嚴肅。) 把請求到的資料 console.log(data) 一下。

經過幾分鐘卡頓,我勒個去,浏覽器怎麼卡死了。耐心等了一會 資料列印出來了:

ajax 請求二進制流 圖檔 檔案 XMLHttpRequest 請求并處理二進制流資料 之最佳實踐

這是什麼乖乖,我滴孩嘞(正統 淮南話)。

第四步思考:怎麼是這樣的資料。Postman 中傳回的是圖檔啊 我的怎麼這樣,對了 看看postman 傳回的是什麼資料。

在postman中選中圖檔 -》右鍵-》檢查 如下圖所示:

ajax 請求二進制流 圖檔 檔案 XMLHttpRequest 請求并處理二進制流資料 之最佳實踐

第五步思考:為什麼我的資料與postman資料不同。為何是亂碼咧? 不對,ajax傳回的資料是什麼?難道編碼被改了?難道不支援二進制流?

一邊想着 一邊打開jquery 官網(抱怨一下 jquery官網真心慢,w3school真心膚淺) 查找ajax datatype資料類型

ajax 請求二進制流 圖檔 檔案 XMLHttpRequest 請求并處理二進制流資料 之最佳實踐

發現竟然沒有二進制資料選項,那是不是傳回的資料被預設以文本形式傳回了。

抱怨:jquery做了這麼久了 一個ajax方法還停留在幾年前的xmlhttprequest 1的版本中,驚人的不支援流檔案!!!

我這還怎麼大肆推行我的前背景完全隔離思想~~。算了不抱怨了,果然是不能靠别人,隻能自己寫了。

樓主依稀記得 xmlhttprequest 2 标準中支援流檔案的,并且應該使用 xhr.response作為傳回 而不是responseText。 那麼開始寫到:

var url = serverUrlBase + "/server/images/" + mapid + "/files/png";'
var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);//get請求,請求位址,是否異步
xhr.setRequestHeader("client_type", "DESKTOP_WEB");
xhr.setRequestHeader("desktop_web_access_key", _desktop_web_access_key);
xhr.onload = function() {
    if (this.status == ) {
        var data = this.response;
        //TODO..........如何接收資料呢。
    }
}
xhr.send();
           

第六步思考: 這樣應該可行,但是怎麼處理請求的資料呢? ???? 這個問題。 對了 html5新特性裡面是不是 提到一個 Blob對象來着。試試看。

通過查閱相關blob資料,查閱 4.6.9 The response attribute 得知 傳回類型應該使用

ajax 請求二進制流 圖檔 檔案 XMLHttpRequest 請求并處理二進制流資料 之最佳實踐

在請求成功的地方 添加以下代碼:

var blob=new Blob(); 
blob=this.response;
           

既然二進制資料拿到了,那麼要把它放在一個 html标簽中,并且應該是img标簽 那麼:代碼應該是

var img = document.createElement("img");
           

img.src = window.URL.createObjectURL(blob); //有問題,将blob加載到img中 由于blob太大 會有性能影響 應該怎麼在加載之後 如何釋放呢:

img.onload = function(e) {
    window.URL.revokeObjectURL(img.src);//釋放。
};
           

然後 将img 放到一個div容器中就可以啦。

$(“#imgcontainer”).html(img); 是的請求處理就應該是這樣。

那麼我們最終的代碼如下:

var url = serverUrlBase + "/server/images/" + mapid + "/files/png";
var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.responseType = "blob";
xhr.setRequestHeader("client_type", "DESKTOP_WEB");
xhr.setRequestHeader("desktop_web_access_key", _desktop_web_access_key);
xhr.onload = function() {
    if (this.status == ) {
        var blob = this.response;
        var img = document.createElement("img");
        img.onload = function(e) {
            window.URL.revokeObjectURL(img.src); 
        };
        img.src = window.URL.createObjectURL(blob);
        $("#imgcontainer").html(img);    
    }
}
xhr.send();
           

結語:這樣樓主解決了 加載二進制流的問題。 結合 上一篇提到的 ajax跨域請求,對于前後端完全分離理念的實作又更近了一步。當然面對安全還是有許多要考慮的問題。

在此過程中,也讓摟着領悟到一點:高階的封裝(ajax)固然好,然而對一些特殊的請求無法處理(請求流檔案),是以還需掌握底層的原理,才能面對苛刻的需求。

總結代碼:

var xhr = new XMLHttpRequest();    
xhr.open("get", url, true);
xhr.responseType = "blob";
xhr.onload = function() {
    if (this.status == ) {
        var blob = this.response;
        var img = document.createElement("img");
        img.onload = function(e) {
            window.URL.revokeObjectURL(img.src); 
        };
        img.src = window.URL.createObjectURL(blob);
     $("#imgcontainer").html(img);
    } 
} 
xhr.send();
           

參考資料:

http://api.jquery.com/jQuery.ajax/ jquery ajax api

https://xhr.spec.whatwg.org/ xmlhttprequest 規範

https://xhr.spec.whatwg.org/#the-responsetype-attribute responsetype傳回類型支援

http://www.zhangxinxu.com/wordpress/2013/10/understand-domstring-document-formdata-blob-file-arraybuffer/ xmlhttprequest 相關學習。

http://www.ruanyifeng.com/blog/2012/09/xmlhttprequest_level_2.html xmlhttprequest 使用指南

本文轉自一位高人的部落格:情郎 Blog

繼續閱讀