日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網(wǎng)為廣大站長(zhǎng)提供免費(fèi)收錄網(wǎng)站服務(wù),提交前請(qǐng)做好本站友鏈:【 網(wǎng)站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(wù)(50元/站),

點(diǎn)擊這里在線(xiàn)咨詢(xún)客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會(huì)員:747

在瀏覽器中異步下載文件,其實(shí)就是把服務(wù)器響應(yīng)的文件先保存在內(nèi)存中。然后再一次下載到磁盤(pán)。第二次下載過(guò)程,就是把內(nèi)存的數(shù)據(jù)IO到磁盤(pán),沒(méi)有網(wǎng)絡(luò)開(kāi)銷(xiāo)。速度極快。

之所以要先保存在內(nèi)存,主要是可以在下載開(kāi)始之前和下載結(jié)束后可以做一些業(yè)務(wù)邏輯(例如:校驗(yàn),判斷),還可以監(jiān)聽(tīng)下載的進(jìn)度。

演示

這里演示一個(gè)Demo,在點(diǎn)擊下載摁鈕后,彈出加loading框。在讀取到服務(wù)器的響應(yīng)的文件后。關(guān)閉loading框。并且在控制臺(tái)中輸出下載的進(jìn)度。

有點(diǎn)像是監(jiān)聽(tīng)文件下載完畢的意思,也只能是像。從內(nèi)存IO到磁盤(pán)的這個(gè)過(guò)程,JS代碼,再也無(wú)法染指過(guò)程。更談不上監(jiān)聽(tīng)了。

Controller

服務(wù)端的下載實(shí)現(xiàn)

import JAVA.io.BufferedInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMApping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
@Controller
@RequestMapping("/download")
public class DownloadController {
		@GetMapping
	public void download (HttpServletRequest request,
							HttpServletResponse response,							@RequestParam("file") String file) throws IOException {
				Path path = Paths.get(file);
		if (Files.notExists(path) || Files.isDirectory(path)) {
			// 文件不存在,或者它是一個(gè)目錄
			response.setStatus(HttpServletResponse.SC_NOT_FOUND);
			return ;
		}
		
		String contentType = request.getServletContext().getMimeType(file);
		if (contentType == null) { 
			// 如果沒(méi)讀取到ContentType,則設(shè)置為默認(rèn)的二進(jìn)制文件類(lèi)型
			contentType = "application/octet-stream";
		}
		
		
		try (BufferedInputStream bufferedInputStream = new BufferedInputStream(Files.newInputStream(path))){
			response.setContentType(contentType);
			response.setHeader("Content-Disposition", "attachment; filename=" + new String(path.getFileName().toString().getBytes("GBK"), "ISO-8859-1"));
			
			// 關(guān)鍵點(diǎn),給客戶(hù)端響應(yīng)Content-Length頭,客戶(hù)端需要用此來(lái)計(jì)算下載進(jìn)度
			response.setContentLengthLong(Files.size(path));
			
			OutputStream outputStream = response.getOutputStream();
			
			byte[] buffer = new byte[8192];
			
			int len = 0;
			
			while ((len = bufferedInputStream.read(buffer)) != -1) {
				outputStream.write(buffer, 0, len);
			}
			
		} catch (IOException e) {
			
		}
	}
}

Index.html

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title>異步下載</title>
	</head>
	<body>
		<input name="name" value="D:\eclipse-jee-2019-12-R-win32-x86_64.zip" placeholder="輸入你要下載的文件路徑" id="file" />
		<button id="button" onclick="downlod();">開(kāi)始下載</button>
	</body>
	<script src="https://cdn.bootcdn.net/ajax/libs/jquery/1.10.0/jquery.min.js"></script>
	<script src="/layer/layer.js"></script>
	<script type="text/JavaScript">
		function downlod(){
			const file = document.querySelector('#file').value;
			if (!file){
				alert('請(qǐng)輸入合法的文件地址');
			}
			
			// 打開(kāi)加載動(dòng)畫(huà)
			const index = layer.load(1, {
  				shade: [0.1,'#fff']
			});
			
			const xhr = new XMLHttpRequest();
			xhr.open('GET', '/download?file=' + encodeURIComponent(file));
			xhr.send(null);
			// 設(shè)置服務(wù)端的響應(yīng)類(lèi)型
			xhr.responseType = "blob";
			// 監(jiān)聽(tīng)下載
			xhr.addEventListener('progress', event => {
				// 計(jì)算出百分比
				const percent  = ((event.loaded / event.total) * 100).toFixed(2);
				console.log(`下載進(jìn)度:${percent}`);
			}, false);
			xhr.onreadystatechange = event => {
				if(xhr.readyState == 4){
					if (xhr.status == 200){
						
						// 獲取ContentType
						const contentType = xhr.getResponseHeader('Content-Type');
						
						// 文件名稱(chēng)
						const fileName = xhr.getResponseHeader('Content-Disposition').split(';')[1].split('=')[1];
						
						// 創(chuàng)建一個(gè)a標(biāo)簽用于下載
						const donwLoadLink = document.createElement('a');
						donwLoadLink.download = fileName;
						donwLoadLink.href = URL.createObjectURL(xhr.response);
						
						// 觸發(fā)下載事件,IO到磁盤(pán)
						donwLoadLink.click();
						
						// 釋放內(nèi)存中的資源
						URL.revokeObjectURL(donwLoadLink.href);
						
						// 關(guān)閉加載動(dòng)畫(huà)
						layer.close(index);
					} else if (response.status == 404){
						alert(`文件:${file} 不存在`);
					} else if (response.status == 500){
						alert('系統(tǒng)異常');
					}
				}
			}
		}
	</script>
</html>

現(xiàn)在的ajax請(qǐng)求,幾乎都是用ES6的fetch,支持異步,而且代碼也更優(yōu)雅。API設(shè)計(jì)得更合理。但是目前為止,好像fetch并沒(méi)有progress事件,也就說(shuō)它不支持監(jiān)聽(tīng)上傳下載的進(jìn)度。所以沒(méi)轍,還是得用XMLHttpRequest。

最后

這種方式弊端也是顯而易見(jiàn),如果文件過(guò)大。那么內(nèi)存就炸了。我覺(jué)得瀏覽器應(yīng)該暴露一個(gè)js的接口。允許通過(guò)異步的方式直接下載文件IO到磁盤(pán),通過(guò)回調(diào)給出下載的進(jìn)度,IO的進(jìn)度。

原文:https://springboot.io/t/topic/2734

分享到:
標(biāo)簽:瀏覽器
用戶(hù)無(wú)頭像

網(wǎng)友整理

注冊(cè)時(shí)間:

網(wǎng)站:5 個(gè)   小程序:0 個(gè)  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會(huì)員

趕快注冊(cè)賬號(hào),推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨(dú)大挑戰(zhàn)2018-06-03

數(shù)獨(dú)一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過(guò)答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫(kù),初中,高中,大學(xué)四六

運(yùn)動(dòng)步數(shù)有氧達(dá)人2018-06-03

記錄運(yùn)動(dòng)步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績(jī)?cè)u(píng)定2018-06-03

通用課目體育訓(xùn)練成績(jī)?cè)u(píng)定