上一個章節,簡要說了以下分片下載的幾個特性。今天主要用示例說明一下pdf.js分片下載。
服務器環境:
php7.2
nginx 1.14
ubuntu 18.04
測試瀏覽器:谷歌瀏覽器 70.0.3538.110(
第一個場景,直接使用pdf 文件
1.1 代碼如下:注意路徑使用的是pdf 文件的物理路徑
$filePath = ‘…/doc/big.pdf’;
這里是舉例,這樣作有一個明顯的缺點,就是容易被盜鏈
getDocument 方法中的 rangeChunkSize 參數,就是設置分塊大小,默認是64k,可以修改這個數字,來改變
這個例子使用的 1664k ,1m 左右來分片,方便測試。您可以根據具體情況,來調整
PDFJS.getDocument({url:url,rangeChunkSize:6553616,disableAutoFetch:0}).
<html>
<head><title>pdf.js展示1,上一頁,下一頁</title></head>
<h1>PDF.js Previous/Next example</h1>
<div>
<button id="prev">Previous</button>
<button id="next">Next</button> <span>Page: <span id="page_num"></span> / <span
id="page_count"></span></span></div>
<canvas id="the-canvas"></canvas>
<script src="../js/pdfjs/pdf.js"></script>
<script src="../js/pdfjs/pdf.worker.js"></script>
<script>
var url = '../doc/big.pdf';
var pdfDoc = null,
pageNum = 1,
pageRendering = false,
pageNumPending = null,
scale = 0.8,
canvas = document.getElementById('the-canvas'),
ctx = canvas.getContext('2d');
/**
* Get page info from document, resize canvas accordingly, and render page.
* @param num Page number.
*/
function renderPage(num) {
pageRendering = true;
// Using promise to fetch the page
pdfDoc.getPage(num).then(function (page) {
var viewport = page.getViewport(scale);
canvas.height = viewport.height;
canvas.width = viewport.width;
// Render PDF page into canvas context
var renderContext = {
canvasContext: ctx,
viewport: viewport
};
var renderTask = page.render(renderContext);
// Wait for rendering to finish
renderTask.promise.then(function () {
pageRendering = false;
if (pageNumPending !== null) {
// New page rendering is pending
renderPage(pageNumPending);
pageNumPending = null;
}
});
});
// Update page counters
document.getElementById('page_num').textContent = num;
}
/**
* If another page rendering in progress, waits until the rendering is
* finised. Otherwise, executes rendering immediately.
*/
function queueRenderPage(num) {
if (pageRendering) {
pageNumPending = num;
} else {
renderPage(num);
}
}
/**
* Displays previous page.
*/
function onPrevPage() {
if (pageNum <= 1) {
return;
}
pageNum--;
queueRenderPage(pageNum);
}
document.getElementById('prev').addEventListener('click', onPrevPage);
/**
* Displays next page.
*/
function onNextPage() {
if (pageNum >= pdfDoc.numPages) {
return;
}
pageNum++;
queueRenderPage(pageNum);
}
document.getElementById('next').addEventListener('click', onNextPage);
/**
* Asynchronously downloads PDF.
*/
PDFJS.getDocument({url:url,rangeChunkSize:65536*16,disableAutoFetch:0}).then(function(pdfDoc_) {
pdfDoc = pdfDoc_;
document.getElementById('page_count').textContent = pdfDoc.numPages;
// Initial/first page rendering
renderPage(pageNum);
});
</script>
</html>
1.2今天第一加載:發現沒有出現分片效果。如果您也遇到這種情況,不要着急,很大程度是因為瀏覽器緩存
1.3 在瀏覽器中,安Ctrl+alt+delte 鍵,清除緩存

1.4 清除緩存后,再次刷新頁面,發現分片下載功能出現了。
后台代碼
<?php
$filePath = '../doc/big.pdf';
//普通的方式處理包裝pdf文件
download_file($filePath);
function download_file($file, $fname = 'chunk.pdf')
{
header("Content-Type: application/octet-stream");
header("Content-Disposition: attachment;filename=$fname");
echo(file_get_contents($file));
}
前台js 調用代碼
。。。。。
var url = 'download.php';
var pdfDoc = null,
pageNum = 1,
pageRendering = false,
pageNumPending = null,
scale = 0.8,
canvas = document.getElementById('the-canvas'),
ctx = canvas.getContext('2d');
。。。。
2.2 經過清理緩存,發現無法達到分片的效果。
初步總結如下,常規的附件處理方式,會影響分片下載的效果
場景3:使用php 結合httprange,實現分片的效果
3.1 這里是從網上搜集到的分片下載php 函數
代碼的核心是,增加head 頭,開啟分片 Header("Accept-Ranges: bytes"); 至於 Http range 如何計算,就比較繁瑣了,這里就不詳細介紹了。有興趣的可以去百度
<?php
$filePath = '../doc/big.pdf';
//分片下載
chunk_download_file($filePath);
/**
* 分篇下載的漢書
*
* @param $file
* @param $fname
*/
function chunk_download_file($file, $fname = 'chunk.pdf')
{
$fhandle = fopen($file, 'rb');//文件句柄
$fsize = filesize($file);//文件大小
//斷點續傳和整個文件下載的判斷,支持多段下載
if (!empty($_SERVER['HTTP_RANGE'])) {
$range = str_replace("=", "-", $_SERVER['HTTP_RANGE']);
$match = explode("-", $range);
$start = $match[1];
$end = !empty($match[2]) ? $match[2] : $fsize - 1;
} else {
$start = 0;
$end = $fsize - 1;
}
if (($end - $start) < ($fsize - 1)) {
fseek($fhandle, $start);
header("HTTP/1.1 206 Partial Content");
header("Content-Length: " . ($end - $start + 1));
header("Content-Range: bytes " . $start . "-" . $end . "/" . $fsize);
} else {
header("HTTP/1.1 200 OK");
header("Content-Length: $fsize");
Header("Accept-Ranges: bytes");
header("Content-Range: bytes " . $start . "-" . $end . "/" . $fsize);
}
header("Content-Type: application/octet-stream");
header("Content-Disposition: attachment;filename=$fname");
if (!feof($fhandle)) {
set_time_limit(0);
$buffer = fread($fhandle, $end - $start + 1);
echo $buffer;
flush();
ob_flush();
}
}
demo 下載路徑:
https://download.csdn.net/download/niedewang/10804164
3.2 清理調瀏覽器緩存,發現這種方式可以達到分片下載的效果
經過測試,谷歌瀏覽器支持的很好,如上圖所示,截圖就是使用的谷歌瀏覽器。
但是firefox 在這種場景下,分片效果不理想。具體原因未知
簡要的總結
1:前期承諾的demo 放出來了,blog貌似會清理連接地址,不知道是否會刪除
2:使用pdf 真實文件路徑,分片兼容性最好。但是地址容易泄漏
3:如果使用php 處理,一般的處理程序,不能達到分片效果。需要結合http range特性,但是不知道什么原因,firefox測試下來,效果不好。谷歌瀏覽器支持的較好,好消息是谷歌瀏覽器現在占用量是最大的。
4:后面有時間了,會介紹以下使用 x-sendfile 的方式處理附件,無論性能還是兼容性都比php 處理要好
---------------------
作者:只看遠方
來源:CSDN
原文:https://blog.csdn.net/niedewang/article/details/84576969
版權聲明:本文為博主原創文章,轉載請附上博文鏈接!
