1. 程式人生 > >前端接收資料流實現圖片預覽效果--ajax 請求二進位制流 圖片 檔案 XMLHttpRequest 請求並處理二進位制流資料 之最佳實踐

前端接收資料流實現圖片預覽效果--ajax 請求二進位制流 圖片 檔案 XMLHttpRequest 請求並處理二進位制流資料 之最佳實踐

本文為轉載文章

原文連結:https://www.cnblogs.com/cdemo/p/5225848.html

首先要謝謝這位大神的無私貢獻!解決了我的問題也完美表達了我當時的心路歷程大笑大笑

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

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

 

需求:在前(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 中選中檔案 在瀏覽器中檢視。

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

 

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

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

 

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

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

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

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

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

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

一邊想著 一邊開啟jquery 官網(抱怨一下 jquery官網真心慢,w3school真心膚淺) 查詢ajax datatype資料型別

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

抱怨: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 == 200) {
                    var data = this.response;
            //TODO...............................................如何接收資料呢。

                }
            }
            xhr.send();

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

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

 

在請求成功的地方 新增以下程式碼:

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 == 200) {
                    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 == 200) { 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 使用指南

 

自己總結的一點問題:

如果在檢查程式碼發現程式碼無誤,卻始終發現預覽效果為空白時請確認一下請求路徑下的圖片否確實存在