下面給大家介紹一下我遇到的一個(gè)坑,如果你也遇到了,那恭喜你,你一定能找到答案:angular2/angular4 如何通過(guò)$http的post方法請(qǐng)求下載二進(jìn)制的Excel文件? (angular1自行百度)
問(wèn)題描述:
后臺(tái)返回的是一個(gè)二進(jìn)制的Excel流,請(qǐng)求頭如下:
Access-Control-Allow-Origin:*
Cache-Control:private
Content-Disposition:attachment;filename=%E9%A9%BE%E9%A9%B6%E5%91%98%E8%AF%84%E5%88%86.xlsx
Content-Type:application/vnd.ms-excel; charset=UTF-8
Date:Thu, 15 Jun 2017 03:19:11 GMT
Server:Microsoft-IIS/8.5
Transfer-Encoding:chunked
X-AspNet-Version:4.0.30319
X-Powered-By:ASP.NET
給的請(qǐng)求方式是post,然后帶一堆的參數(shù),現(xiàn)在求如何請(qǐng)求?
當(dāng)時(shí)覺(jué)得后臺(tái)應(yīng)該是返回的是一個(gè)Excel文件下載的地址,于是按照正常的請(qǐng)求發(fā)起請(qǐng)求,結(jié)果是然并卵,報(bào)錯(cuò)了,返回?cái)?shù)據(jù)如下:
返回結(jié)果是一個(gè)二進(jìn)制流,還會(huì)有一個(gè)請(qǐng)求失敗的提示
排除后端問(wèn)題,那前端應(yīng)該怎么請(qǐng)求呢?
當(dāng)時(shí)想到的第一種方式是修改響應(yīng)頭:
Content-Type:application/vnd.ms-excel; charset=UTF-8
原來(lái)的響應(yīng)頭是Content-Type: application/json,改成xsl對(duì)應(yīng)的二進(jìn)制響應(yīng)頭應(yīng)該就沒(méi)錯(cuò)了吧,結(jié)果依然是然并卵,直接給我報(bào)500錯(cuò)誤
于是乎,決定谷歌之,百度之,發(fā)現(xiàn)處理這種辦法的大多數(shù)是這樣的:
$http({
url: 'your/webservice',
method: "POST",
data: json, //this is your json data string
headers: {
'Content-type': 'application/json'
},
responseType: 'arraybuffer'
}).success(function (data, status, headers, config) {
var blob = new Blob([data], {type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"});
var objectUrl = URL.createObjectURL(blob);
window.open(objectUrl);
}).error(function (data, status, headers, config) {
//upload failed
});
基本上大部分方法跟上面的大同小異,于是按著這個(gè)方法試了試,其中的重點(diǎn)配置是 responseType: 'arraybuffer', 因?yàn)閍ngular的http模塊里面有對(duì)responseType有定義:
responseType: ResponseContentType | null;
找到ResponseContentType:
export declare enum ResponseContentType {
Text = 0,
Json = 1,
ArrayBuffer = 2,
Blob = 3,
}
原來(lái)它還有這幾個(gè)參數(shù),那ArrayBuffer 對(duì)應(yīng)就是responseType: 2, 依然是沒(méi)有用,結(jié)果跟直接用post請(qǐng)求一樣
如果你也經(jīng)歷了這些,往下看吧!
這是我在想,ResponseContentType 里面的其他的屬性都是干嘛的, 前面2個(gè)很好理解,一個(gè)是文本格式的, 一個(gè)是json格式的,那ArrayBuffer和Blob是什么意思呢?我只是簡(jiǎn)單的將一下,想深入了解,可以看看張?chǎng)涡竦?理解DOMString冕臭、Document才睹、FormData蛛砰、Blob肤无、File蕉世、ArrayBuffer數(shù)據(jù)類型
ArrayBuffer表示二進(jìn)制數(shù)據(jù)的原始緩沖區(qū)见坑,該緩沖區(qū)用于存儲(chǔ)各種類型化數(shù)組的數(shù)據(jù),ArrayBuffer是二進(jìn)制數(shù)據(jù)通用的固定長(zhǎng)度容器琼蚯。
Blob表示二進(jìn)制大對(duì)象,專門存放二進(jìn)制數(shù)據(jù)违施。
額,聽(tīng)不懂叹话?可以這么理解偷遗,ArrayBuffer就是作為數(shù)據(jù)源提前寫入在內(nèi)存中,就是提前釘死在某個(gè)區(qū)域驼壶,長(zhǎng)度也固定氏豌,萬(wàn)年不變,Blob是個(gè)更高一級(jí)的大分類热凹,包含ArrayBuffer泵喘,還有更多;
還有一種理解就是XMLHttpRequest 第二版允許服務(wù)器返回二進(jìn)制數(shù)據(jù)般妙,這時(shí)分成兩種情況纪铺。如果明確知道返回的二進(jìn)制數(shù)據(jù)類型,可以把返回類型(responseType)設(shè)為arraybuffer碟渺;如果不知道鲜锚,就設(shè)為blob。
反正不管怎么樣吧苫拍,試一試blob芜繁,于是就有我最終的代碼:
download(url?:string, form?:any){
this.downloadHeader;
return this.http.post(url, form, this.options).map(res => res.json).catch(this.handleError);
}
downloadHeader{
if (localStorage.getItem(environment.local_storage_account)) {
this.headers = new Headers({'token': JSON.parse(localStorage.getItem(environment.local_storage_account)).Token });
this.options = new RequestOptions({ headers: this.headers, responseType: 3 });
}
}
每個(gè)人的代碼寫法不一樣,請(qǐng)忽略其他的,只關(guān)注responseType: 3
最后返回的response是:
Blob {size: 4384, type: "application/vnd.ms-excel"}
那就可以用大家常用的blob方法來(lái)下載了:
var blob = new Blob([data], {type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"});
var objectUrl = URL.createObjectURL(blob);
window.open(objectUrl);
這里有一個(gè)問(wèn)題,就是很多瀏覽器可能會(huì)墻掉彈窗,導(dǎo)致你的文件沒(méi)法正常下載,所以我們用a標(biāo)簽的形式來(lái)下載,思路就是成功后新建一個(gè)帶下載地址的a標(biāo)簽,然后被動(dòng)觸發(fā)點(diǎn)擊:
var blob = new Blob([res], {type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"});
var objectUrl = URL.createObjectURL(blob);
var a = document.createElement('a');
document.body.appendChild(a);
a.setAttribute('style', 'display:none');
a.setAttribute('href', objectUrl);
a.setAttribute('download', fileName);
a.click;
URL.revokeObjectURL(objectUrl);
結(jié)束后釋放url,好了,大概的思路就是這樣了,如果你還有什么不明白的,歡迎給我留言,我會(huì)盡快給你回復(fù)!