fetch的文件流下载及下载进度获取

  • 下载过程中,获取进度,fetch API并没有提供类似xhr和ajax的 progress所以用 getReader()来循环读取大小
	 let  size = 0;
		  fetch( URL() + `/sys/file/download/${uuid}`,{
			method: 'GET',
			headers:{
				token,
			}
		})
		.then(response => {
			if(response.ok){
				return response;
			}else{
				console.log("请求失败")
			}
		})
			// 取出body
			.then(response => response.body)
			.then(body => {
			  const reader = body.getReader();

				  return new ReadableStream({
					start(controller) {
					  return pump();

					  function pump() {
						return reader.read().then(res => {   //res  ({ done, value }) 
						  // 读不到更多数据就关闭流
						  console.log(res,"res");
						  const {done,value } = res;
						  if (done) {
							  console.log("end")
							controller.close();
							// return;
						  }
							size += value.length  || 0;
							console.log(size,"size")
						  // 将下一个数据块置入流中
						  controller.enqueue(value);
						  return pump();
						});
					  }
					}
				  })
				})
				.then(stream => new Response(stream))
				.then(response => that.savingFile(response,fileName))
				.catch(err => console.error(err));
  • 上一步中接收到文件流后,通过Blob和a标签进行下载
 savingFile = (response,fileName) => {
		 const that = this;
		 response.blob().then( blob => {	 
		 	if(typeof FileReader === 'undefined'){
		 		notification.open({
		 			 message:'您的浏览器不支持 FileReader,请升级浏览器',
		 			 icon: <Icon type="smile" style={{ color: '#108ee9' }} />
		 		})
		 	}
		 	const reader = new FileReader();									
		 	reader.addEventListener("loadend", function() {		
		 				let resu = '';
		 				try{
		 					resu = JSON.parse( reader.result);
		 					 // resu = eval('('+ reader.result + ')')
		 					if(resu.code == 500){
		 						notification.open({
		 							 message:resu.msg,
		 							  icon: <Icon type="smile" style={{ color: '#108ee9' }} />
		 						})
		 					}else if(resu.code == 401){
		 						notification.error({
		 							 message:resu.msg
		 						})
		 					}
		 				}catch(e){
		 					//捕获错误 说明是文本字符串 
		 					resu = reader.result;
		 					downloadBlob(blob,fileName);
		 				}
		 			
		 	});
		 	reader.readAsText(blob);	
		 		 
		 		 //下载
		 		 function downloadBlob(blob,fileName){
		 				let blobUrl = window.URL.createObjectURL(blob);
		 				let a = document.createElement('a');
		 				a.href = blobUrl;
		 				a.target = '_blank';
		 				a.style.display = 'none'
		 				document.body.appendChild(a)
		 				a.download = fileName;
		 				a.click();
		 				window.URL.revokeObjectURL(blobUrl);
		 				document.body.removeChild(a)
		 				
		 				that.setState({
		 					downloading:false
		 				})
		 		 }
		 })
	 }

总结一下: 这种前端下载的方式,感觉体验还不是很好。主要考虑是文件流的下载方式,是先下载完全部数据才弹出保存窗口,而大部分软件下载的网站是用a标签直接下载的。这样是先弹出窗口,再利用浏览器的下载工具进行下载,虽然少了一些定制显示,但用户体验上应该会好一点。 再找个下载文件的网站参考参考。

原文地址:https://www.cnblogs.com/chengyunshen/p/11376735.html