摘要:主要用于存儲(chǔ)速度不同步的設(shè)備或者優(yōu)先級(jí)不同的設(shè)備之間傳辦理數(shù)據(jù)的區(qū)域。機(jī)制,意味在之前,建立了一新的隊(duì)列,數(shù)據(jù)必須經(jīng)過(guò)該隊(duì)列。當(dāng)需要下載的文件很大的時(shí)候,這種方式將消耗大量?jī)?nèi)存,甚至引發(fā)進(jìn)程超時(shí)或崩潰,接下來(lái)就使用到。
一、普通文件下載
①laravel框架HTTP響應(yīng)的download方法
$pathToFile = "myfile.csv";//參數(shù)一:絕對(duì)路徑 $downloadName = "downloadFile.csv";//參數(shù)二:下載后的文件名 //download 參數(shù)三:HTTP頭信息 return response()->download($pathToFile, $downloadName);
②PHP實(shí)現(xiàn)
$pathToFile = "myfile.csv";//文件絕對(duì)路徑 $downloadName = "downloadFile.csv";//下載后的文件名 //輸入文件標(biāo)簽 Header("Content-type: application/octet-stream"); Header("Accept-Ranges: bytes"); Header("Accept-Length: " . filesize($pathToFile)); Header("Content-Disposition: filename=" . $downloadName); //輸出文件內(nèi)容 $file = fopen($pathToFile, "r"); echo fread($file, filesize($pathToFile)); fclose($file); //或 //readfile($pathToFile);
其中fread()與readfile()的區(qū)別可以參考https://segmentfault.com/q/10...
但是有時(shí)候?yàn)榱斯?jié)省帶寬,避免瞬時(shí)流量過(guò)大而造成網(wǎng)絡(luò)堵塞,就要考慮下載限速的問(wèn)題
$pathToFile = "myfile.csv";//文件絕對(duì)路徑 $downloadName = "downloadFile.csv";//下載后的文件名 $download_rate = 30;// 設(shè)置下載速率(30 kb/s) if (file_exists($pathToFile) && is_file($pathToFile)) { header("Cache-control: private");// 發(fā)送 headers header("Content-Type: application/octet-stream"); header("Content-Length: " . filesize($pathToFile)); header("Content-Disposition: filename=" . $downloadName); flush();// 刷新內(nèi)容 $file = fopen($pathToFile, "r"); while (!feof($file)) { print fread($file, round($download_rate * 1024));// 發(fā)送當(dāng)前部分文件給瀏覽者 flush();// flush 內(nèi)容輸出到瀏覽器端 sleep(1);// 終端1秒后繼續(xù) } fclose($file);// 關(guān)閉文件流 } else { abort(500, "文件" . $pathToFile . "不存在"); }
此時(shí)出現(xiàn)一個(gè)問(wèn)題,當(dāng)$download_rate>1kb時(shí),文件正常下載;當(dāng)$download_rate<1kb時(shí),文件要等一會(huì)兒才下載,究其原因是因?yàn)閎uffer的問(wèn)題。
buffer是一個(gè)內(nèi)存地址空間,Linux系統(tǒng)默認(rèn)大小一般為4096(1kb),即一個(gè)內(nèi)存頁(yè)。主要用于存儲(chǔ)速度不同步的設(shè)備或者優(yōu)先級(jí)不同的設(shè)備之間傳辦理數(shù)據(jù)的區(qū)域。舉個(gè)例子,你打開(kāi)文本編輯器編輯一個(gè)文件的時(shí)候,你每輸入一個(gè)字符,操作系統(tǒng)并不會(huì)立即把這個(gè)字符直接寫入到磁盤,而是先寫入到buffer,當(dāng)寫滿了一個(gè)buffer的時(shí)候,才會(huì)把buffer中的數(shù)據(jù)寫入磁盤。同樣的道理,當(dāng)執(zhí)行echo,print的時(shí)候,輸出并沒(méi)有立即通過(guò)tcp傳給客戶端瀏覽器顯示,而是將數(shù)據(jù)寫入php buffer。php output_buffering機(jī)制,意味在tcp buffer之前,建立了一新的隊(duì)列,數(shù)據(jù)必須經(jīng)過(guò)該隊(duì)列。當(dāng)一個(gè)php buffer寫滿的時(shí)候,腳本進(jìn)程會(huì)將php buffer中的輸出數(shù)據(jù)交給系統(tǒng)內(nèi)核交由tcp傳給瀏覽器顯示。所以,數(shù)據(jù)會(huì)依次寫到這幾個(gè)地方echo/pring -> php buffer -> tcp buffer -> browser。資料:http://blog.csdn.net/superhos...
在沒(méi)有開(kāi)啟緩存時(shí),腳本輸出的內(nèi)容都在服務(wù)器端處于等待輸出的狀態(tài),flush()可以將等待輸出的內(nèi)容立即發(fā)送到客戶端。
開(kāi)啟緩存后,腳本輸出的內(nèi)容存入了輸出緩存中,這時(shí)沒(méi)有處于等待輸出狀態(tài)的內(nèi)容,你直接使用flush()不會(huì)向客戶端發(fā)出任何內(nèi)容。而ob_flush()的作用就是將本來(lái)存在輸出緩存中的內(nèi)容取出來(lái),設(shè)置為等待輸出狀態(tài),但不會(huì)直接發(fā)送到客戶端,這時(shí)你就需要先使用ob_flush()再使用flush(),客戶端才能立即獲得腳本的輸出。
以及這篇文章同樣講述了ob_flush()和flush()的區(qū)別http://www.laruence.com/2010/...
但是這種方法將文件內(nèi)容從磁盤經(jīng)過(guò)一個(gè)固定的 buffer 去循環(huán)讀取到內(nèi)存,再發(fā)送給前端 web 服務(wù)器,最后才到達(dá)用戶。當(dāng)需要下載的文件很大的時(shí)候,這種方式將消耗大量?jī)?nèi)存,甚至引發(fā) php 進(jìn)程超時(shí)或崩潰,接下來(lái)就使用到X-Sendfile。
三、X-SendfileX-Sendfile 是一種將文件下載請(qǐng)求由后端應(yīng)用轉(zhuǎn)交給前端 web
服務(wù)器處理的機(jī)制,它可以消除后端程序既要讀文件又要處理發(fā)送的壓力,從而顯著提高服務(wù)器效率,特別是處理大文件下載的情形下。
我是用的nginx,所以apache請(qǐng)參考https://tn123.org/mod_xsendfile/
①首先在配置文件中添加
location /download/ { internal; root /some/path;//絕對(duì)路徑 }
internal 表示這個(gè)路徑只能在 Nginx 內(nèi)部訪問(wèn),不能用瀏覽器直接訪問(wèn)防止未授權(quán)的下載
注意添加在location / {...}的前面
這樣你在代碼中使用時(shí),文件路徑就可以寫成“/download/myfile.csv”
②重啟Nginx,寫代碼
$pathToFile = "myfile.csv";//文件絕對(duì)路徑 $downloadName = "downloadFile.csv";//下載后的文件名 $download_rate = 30;// 設(shè)置下載速率(30 kb/s) if (file_exists($pathToFile) && is_file($pathToFile)) { return (new Response())->withHeaders([ "Content-Type" => "application/octet-stream", "Content-Disposition" => "attachment;filename=" . $downloadName, "X-Accel-Redirect" => $pathToFile,//讓Xsendfile發(fā)送文件 "X-Sendfile" => $pathToFile, "X-Accel-Limit-Rate" => $download_rate, ]); }else { abort(500, "文件" . $pathToFile . "不存在"); }
如果你還想了解更多關(guān)于X-sendfile,請(qǐng)自行查閱
記得關(guān)注我呦
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/26165.html
摘要:簡(jiǎn)述交互主要分為請(qǐng)求和響應(yīng)兩種方式。狀態(tài)碼構(gòu)建響應(yīng)時(shí),最先應(yīng)做的是標(biāo)識(shí)請(qǐng)求是否成功處理的狀態(tài),可通過(guò)設(shè)置屬性,該屬性使用一個(gè)有效的狀態(tài)碼。 簡(jiǎn)述 HTTP交互主要分為 request(請(qǐng)求) 和 response(響應(yīng)) 兩種方式。 對(duì)于Yii2來(lái)說(shuō),HTTP的request請(qǐng)求是用 YII::$app->request 來(lái)表示的對(duì)象,這是Yii提供的處理HTTP的request請(qǐng)求的...
摘要:但是,你的連接數(shù)限制配置為允許單個(gè)連接數(shù),單個(gè)連接數(shù)最大帶寬為。就降低單個(gè)連接數(shù)帶寬吧要知道大家誰(shuí)沒(méi)事會(huì)用瀏覽器自帶下載器下載呢注本文只探討限速模塊在不同業(yè)務(wù)下的限速彩蛋偶爾發(fā)現(xiàn),將連接數(shù)限制為迅雷不能高速下載了。 nginx 內(nèi)置模塊限速怎么使用就不多說(shuō)了,今天來(lái)說(shuō)說(shuō)連接數(shù)和單個(gè)連接數(shù)限速的事。 場(chǎng)景:A公司有100人,A公司只有一個(gè)公網(wǎng)IP,假設(shè)A公司可能有100個(gè)人同時(shí)在下載你的...
摘要:但是,你的連接數(shù)限制配置為允許單個(gè)連接數(shù),單個(gè)連接數(shù)最大帶寬為。就降低單個(gè)連接數(shù)帶寬吧要知道大家誰(shuí)沒(méi)事會(huì)用瀏覽器自帶下載器下載呢注本文只探討限速模塊在不同業(yè)務(wù)下的限速彩蛋偶爾發(fā)現(xiàn),將連接數(shù)限制為迅雷不能高速下載了。 nginx 內(nèi)置模塊限速怎么使用就不多說(shuō)了,今天來(lái)說(shuō)說(shuō)連接數(shù)和單個(gè)連接數(shù)限速的事。 場(chǎng)景:A公司有100人,A公司只有一個(gè)公網(wǎng)IP,假設(shè)A公司可能有100個(gè)人同時(shí)在下載你的...
摘要:對(duì)于那些不想掛機(jī)還想使用高速下載的用戶來(lái)說(shuō),只要付費(fèi)即可。元,元,元,滿足你的不同下載需求,如果你是周末偶爾看看電影,偶爾下載點(diǎn)學(xué)習(xí)資料,那么元的流量包最合適不過(guò)。 pandownload會(huì)被限速,這眾所周知,先看下我這個(gè)網(wǎng)盤的下載速度吧showImg(https://segmentfault.com/img/bVbvc7I); 下面我說(shuō)說(shuō)為啥我這個(gè)支持免登陸下載,而且不受到百度網(wǎng)盤的...
摘要:對(duì)于那些不想掛機(jī)還想使用高速下載的用戶來(lái)說(shuō),只要付費(fèi)即可。元,元,元,滿足你的不同下載需求,如果你是周末偶爾看看電影,偶爾下載點(diǎn)學(xué)習(xí)資料,那么元的流量包最合適不過(guò)。 pandownload會(huì)被限速,這眾所周知,先看下我這個(gè)網(wǎng)盤的下載速度吧showImg(https://segmentfault.com/img/bVbvc7I); 下面我說(shuō)說(shuō)為啥我這個(gè)支持免登陸下載,而且不受到百度網(wǎng)盤的...
閱讀 1229·2021-11-25 09:43
閱讀 1984·2021-11-11 10:58
閱讀 1199·2021-11-08 13:18
閱讀 2703·2019-08-29 16:25
閱讀 3524·2019-08-29 12:51
閱讀 3321·2019-08-29 12:30
閱讀 760·2019-08-26 13:24
閱讀 3696·2019-08-26 10:38