Pro 版本
Webview — 深入參考
本頁記錄公開的 NextPDF\Pro\Webview 介面、byte-range 請求/回應模型,以及超出公開登陸頁面之外的確切失敗模式。
可用性與授權
標題為「可用性與授權」的區段此能力隨 NextPDF Pro(nextpdf/pro)出貨,並以 Pro 級授權封套(license envelope)啟用。缺少該權益的部署不會載入此能力的類別。比較各版本並取得授權。
沒有個別功能的授權旗標;程式碼隨 Pro 版本一併出貨。PSR-17 ResponseFactoryInterface / StreamFactoryInterface 與主體媒體型別都是執行階段的建構子參數,而非授權控制。
公開 API 介面
標題為「公開 API 介面」的區段composer require nextpdf/proNextPDF\Pro\Webview 下的公開型別:
LinearizedDocument——一份已驗證、備妥交付的線性化 PDF。ByteRangeResponder——RFC 9110 byte-range HTTP responder。ByteRange——某個表示上一個可滿足的包含式 byte range。FirstPageProber——「在完整下載之前的第一頁」結構性證明。
NextPDF\Pro\Webview\Exception 下的例外型別:
WebviewException(marker interface)、UnsupportedDocumentException、RangeNotSatisfiableException。
LinearizedDocument
標題為「LinearizedDocument」的區段一個帶有 private constructor 的 final readonly 類別;請透過具名建構子實例化。
static fromBytes(string $bytes): self——透過 Core 的讀取端LinearizationView::fromPdf()解析這些位元組。當文件未線性化、宣告的/L與實際位元組長度不符,或/E第一頁結尾偏移不是檔案內的正向偏移時,擲出UnsupportedDocumentException。length(): int——以位元組計的文件長度。firstPagePrefixLength(): int——含完整第一頁的最小前導前綴:/E偏移,夾限至檔案長度。firstPageByteRange(): ByteRange——交付第一頁的包含式範圍[0, /E - 1]。僅在前綴為空時擲出RangeNotSatisfiableException(縱深防禦;fromBytes()已保證0 < /E <= length)。slice(int $firstByte, int $lastByte): string——使用包含式偏移的嚴格程式化切片;越界時擲出RangeNotSatisfiableException。etag(): string——位元組的強而確定性的 SHA-256 entity-tag,在建構時記憶化一次。
公開 readonly 屬性:bytes(原始 PDF 位元組)與 view(Core 的 LinearizationView)。
ByteRangeResponder
標題為「ByteRangeResponder」的區段一個僅針對 PSR-7 / PSR-17 實作的 final readonly 類別。
__construct(ResponseFactoryInterface $responses, StreamFactoryInterface $streams, string $contentType = 'application/pdf')——當$contentType含控制字元時擲出InvalidArgumentException(它會被內插進回應與 multipart 部分標頭;CR/LF 與其他控制位元組會被拒絕以防止標頭注入)。respond(LinearizedDocument $document, ServerRequestInterface $request): ResponseInterface——使用文件自身的ETag,回答一份線性化文件的範圍請求。respondToBytes(string $bytes, ServerRequestInterface $request, ?string $etag = null): ResponseInterface——回答任意位元組的範圍請求(一個應支援範圍但不必線性化的表示)。當為null時,ETag由位元組推導。firstPageResponse(LinearizedDocument $document): ResponseInterface——建構一個恰好攜帶第一頁 byte range 的206;亦即「在完整下載之前的第一頁」的伺服器推送形式。
ByteRange
標題為「ByteRange」的區段一個用於單一可滿足包含式 byte range 的 final readonly 值物件(RFC 9110 §14.1.2)。
__construct(int $firstByte, int $lastByte, int $contentLength)——強制可滿足性0 <= firstByte <= lastByte <= contentLength - 1;否則擲出RangeNotSatisfiableException。length(): int——包含式跨度(lastByte - firstByte + 1),永遠>= 1。contentRange(): string——RFC 9110 §14.4 的Content-Range欄位值bytes first-last/length。
公開 readonly 屬性:firstByte、lastByte、contentLength。
FirstPageProber
標題為「FirstPageProber」的區段一個由 LinearizedDocument 建構的 final readonly 類別。
prefixLength(): int——算繪第一頁所需的最小前導位元組數。prefixFraction(): float——前綴占整份檔案的比例(0.0–1.0);對一個零長度檔案回傳1.0。hintStreamWithinPrefix(): bool——主要的 hint stream 物件是否完全落在第一頁前綴之內(使前綴本身就讓讀取端能定位第 1 頁物件)。hint stream 必須有正向長度。isFirstPageSelfContained(): bool——合併的結構性證明:一個落在檔案內、且完全含有 hint stream 的正向前綴。
byte-range 請求/回應模型
標題為「byte-range 請求/回應模型」的區段ByteRangeResponder 遵循 RFC 9110 §14。在計算長度與一個強 SHA-256 ETag 之後,它會讀取 Range 與 If-Range 標頭並決定:
| 條件 | 狀態 | 備註 |
|---|---|---|
沒有適用的 Range,或 If-Range 與當前強 ETag 不符 | 200 OK | 完整主體。只有強 entity-tag 形式的 If-Range 會被遵守(RFC 9110 §13.1.5)。 |
無法辨識的範圍單位或語法上無效的 Range | 200 OK | 標頭被忽略(RFC 9110 §14.2)。 |
| 一個可滿足的範圍 | 206 Partial Content | 攜帶 Content-Range。 |
| 多個可滿足的範圍 | 206 Partial Content | 帶有一個推導出之邊界的 multipart/byteranges。 |
| 有效的 byte range,但無一可滿足 | 416 Range Not Satisfiable | 攜帶 Content-Range: bytes */length(RFC 9110 §15.3.7)。 |
每個回應都會通告 Accept-Ranges: bytes 與強 ETag。200 與 206 回應也會設定 Content-Type 與 Content-Length。
範圍解析僅接受 bytes= 單位。它支援明確的 first-last、開放結尾的 first-(夾限至結尾),以及後綴 -N(最後 N 個位元組;一個至少與表示一樣大的後綴會選取其全部)。一個裸的 -(或任何其他格式不良的規格)會讓整個 Range 標頭在語法上無效,因此該標頭被忽略並回傳完整的 200 OK 表示。一個 -0 後綴,或任何首偏移在結尾處或之後的規格,是一個不可滿足的規格並被丟棄;若標頭中沒有任何規格可滿足,回應即為 416 Range Not Satisfiable。較大的十進位偏移在比較時不依賴整數溢位飽和,因此一個 30 位數的 Range 值會被以平台無關的方式處理。重疊的可滿足範圍會在任何主體被建構之前先被合併;真正相異(不重疊)的範圍會被保留為各自獨立的 multipart 部分。
失敗模式與例外模型
標題為「失敗模式與例外模型」的區段WebviewException 是一個擴充 Throwable 的 marker interface;catch 它以一致地處理整個子系統。兩個具體例外都實作它。
UnsupportedDocumentException(擴充InvalidArgumentException)——當位元組不是一份可用的線性化文件時,由LinearizedDocument::fromBytes()引發。具名建構子:notLinearized()(無/Linearized參數字典)、lengthMismatch($declaredLength, $actualLength)(宣告的/L與實際長度不符——被截斷、透過超出/L的增量更新被附加,或不符規範),以及malformedFirstPageOffset($firstPageEndOffset, $length)(/E偏移不是檔案內的正向偏移)。RangeNotSatisfiableException(擴充OutOfRangeException)——程式化切片錯誤,當一個包含式範圍落在文件之外時,由ByteRange::__construct()與LinearizedDocument::slice()/firstPageByteRange()引發。具名建構子:outOfBounds($firstByte, $lastByte, $length)。
HTTP responder 不會為用戶端的 Range 標頭擲出 RangeNotSatisfiableException——一個不可滿足的 HTTP 範圍是一個 416 回應(RFC 9110 §15.3.7),而非例外。該例外保留給直接的程式化切片,在那裡一個越界的請求是呼叫端的錯誤。當設定好的 contentType 含控制字元時,ByteRangeResponder::__construct() 會擲出一個純粹的 InvalidArgumentException(而非 WebviewException)。
阻斷服務強化
標題為「阻斷服務強化」的區段responder 會為每個請求所遵守的相異合併(coalesced)範圍數目設上限(multipart range-amplification 這一類,Apache HTTPD CVE-2011-3192)。當一個請求要求比合併範圍上限更多,或比整份表示更多的總位元組時,Range 會被忽略,並回傳一個完整的 200。multipart 邊界會被確定性地推導,並重新推導直到它保證不會出現在主體內,在排除邊界碰撞的同時保留可重現的輸出。
一致性
標題為「一致性」的區段byte-range 行為遵循 RFC 9110(HTTP Semantics):§14(範圍請求)、§13.1.5(If-Range)、§14.4(Content-Range)與 §15.3.7(416)。線性化文件排版是 ISO 32000-2 Annex F 的 Fast Web View 模型。本模組除了其測試所驗證的行為之外,不主張任何進一步的外部條款識別碼。
邊界案例與 FIPS 模式行為
標題為「邊界案例與 FIPS 模式行為」的區段- 當不需要第一頁語意時,
respondToBytes()會在任意位元組上提供範圍。 - 一個
If-RangeHTTP-date 驗證器會被視為不符 → 完整的200(用戶端只是重新抓取)。 ETag是一個純粹用作強快取驗證器的 SHA-256 雜湊;本模組不進行任何簽署或其他密碼學運算,也未定義任何 FIPS 特定行為。
發佈邊界
標題為「發佈邊界」的區段本頁僅記錄外部可觀察的行為與受支援的公開 API 介面。內部命名空間路徑、輔助類別、機制表格、runbook 檔名與工單前綴均不在範圍內。