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

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

點擊這里在線咨詢客服
新站提交
  • 網站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

在瀏覽器中異步下載文件,其實就是把服務器響應的文件先保存在內存中。然后再一次下載到磁盤。第二次下載過程,就是把內存的數據IO到磁盤,沒有網絡開銷。速度極快。

之所以要先保存在內存,主要是可以在下載開始之前和下載結束后可以做一些業務邏輯(例如:校驗,判斷),還可以監聽下載的進度。

演示

這里演示一個Demo,在點擊下載摁鈕后,彈出加loading框。在讀取到服務器的響應的文件后。關閉loading框。并且在控制臺中輸出下載的進度。

有點像是監聽文件下載完畢的意思,也只能是像。從內存IO到磁盤的這個過程,JS代碼,再也無法染指過程。更談不上監聽了。

Controller

服務端的下載實現

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)) {
			// 文件不存在,或者它是一個目錄
			response.setStatus(HttpServletResponse.SC_NOT_FOUND);
			return ;
		}
		
		String contentType = request.getServletContext().getMimeType(file);
		if (contentType == null) { 
			// 如果沒讀取到ContentType,則設置為默認的二進制文件類型
			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"));
			
			// 關鍵點,給客戶端響應Content-Length頭,客戶端需要用此來計算下載進度
			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();">開始下載</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('請輸入合法的文件地址');
			}
			
			// 打開加載動畫
			const index = layer.load(1, {
  				shade: [0.1,'#fff']
			});
			
			const xhr = new XMLHttpRequest();
			xhr.open('GET', '/download?file=' + encodeURIComponent(file));
			xhr.send(null);
			// 設置服務端的響應類型
			xhr.responseType = "blob";
			// 監聽下載
			xhr.addEventListener('progress', event => {
				// 計算出百分比
				const percent  = ((event.loaded / event.total) * 100).toFixed(2);
				console.log(`下載進度:${percent}`);
			}, false);
			xhr.onreadystatechange = event => {
				if(xhr.readyState == 4){
					if (xhr.status == 200){
						
						// 獲取ContentType
						const contentType = xhr.getResponseHeader('Content-Type');
						
						// 文件名稱
						const fileName = xhr.getResponseHeader('Content-Disposition').split(';')[1].split('=')[1];
						
						// 創建一個a標簽用于下載
						const donwLoadLink = document.createElement('a');
						donwLoadLink.download = fileName;
						donwLoadLink.href = URL.createObjectURL(xhr.response);
						
						// 觸發下載事件,IO到磁盤
						donwLoadLink.click();
						
						// 釋放內存中的資源
						URL.revokeObjectURL(donwLoadLink.href);
						
						// 關閉加載動畫
						layer.close(index);
					} else if (response.status == 404){
						alert(`文件:${file} 不存在`);
					} else if (response.status == 500){
						alert('系統異常');
					}
				}
			}
		}
	</script>
</html>

現在的ajax請求,幾乎都是用ES6的fetch,支持異步,而且代碼也更優雅。API設計得更合理。但是目前為止,好像fetch并沒有progress事件,也就說它不支持監聽上傳下載的進度。所以沒轍,還是得用XMLHttpRequest。

最后

這種方式弊端也是顯而易見,如果文件過大。那么內存就炸了。我覺得瀏覽器應該暴露一個js的接口。允許通過異步的方式直接下載文件IO到磁盤,通過回調給出下載的進度,IO的進度。

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

分享到:
標簽:瀏覽器
用戶無頭像

網友整理

注冊時間:

網站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網站吧!
最新入駐小程序

數獨大挑戰2018-06-03

數獨一種數學游戲,玩家需要根據9

答題星2018-06-03

您可以通過答題星輕松地創建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數有氧達人2018-06-03

記錄運動步數,積累氧氣值。還可偷

每日養生app2018-06-03

每日養生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定