Ir al contenido
getnextpdf.com

Pro edición

Webview

Webview entrega un PDF linealizado (Fast Web View) por HTTP, de modo que un cliente pueda empezar a renderizar la página 1 a partir de un pequeño prefijo inicial mientras el resto del archivo todavía está en tránsito. Envuelve los bytes en bruto como un LinearizedDocument, responde a las solicitudes Range con respuestas de contenido parcial RFC 9110 a través de un ByteRangeResponder PSR-7, y puede demostrar (mediante FirstPageProber) que la primera página está contenida por completo en el prefijo.

Esta capacidad se incluye en NextPDF Pro (nextpdf/pro) y se activa con un sobre de licencia de nivel Pro. Una implementación sin ese derecho no carga las clases de la capacidad. Compare ediciones y obtenga una licencia.

No hay ningún indicador de licencia por característica independiente. El responder se conecta a sus propias fábricas PSR-17 en tiempo de ejecución —una ResponseFactoryInterface y una StreamFactoryInterface— y el tipo de medio toma por defecto application/pdf como argumento del constructor, no como un interruptor de licencia.

Ventana de terminal
composer require nextpdf/pro

El código reside bajo el espacio de nombres NextPDF\Pro\Webview.

Un PDF linealizado se dispone de modo que la primera página del documento —el diccionario de parámetros de linealización, el flujo de pistas primario y los objetos de la página 1— se sitúa en una sección inicial que termina en el desplazamiento /E. Webview convierte esa disposición en entrega progresiva.

LinearizedDocument::fromBytes() analiza los bytes a través del LinearizationView del lado de lectura de Core (Pro nunca reimplementa el análisis de linealización) y rechaza cualquier cosa que no sea un documento linealizado utilizable: que no esté linealizado en absoluto, una longitud /L declarada que no coincide con la longitud real en bytes, o un desplazamiento /E de fin de primera página que no es un desplazamiento positivo dentro del archivo. Por tanto, la construcción es total: una vez que se dispone de un LinearizedDocument, todo desplazamiento que expone es confiable.

ByteRangeResponder responde entonces a una solicitud HTTP. Está implementado únicamente contra PSR-7 / PSR-17, sin acoplamiento a ningún framework. Siempre anuncia Accept-Ranges: bytes y un ETag SHA-256 fuerte y determinista, analiza la cabecera Range del cliente según RFC 9110 §14, y devuelve un 200 OK completo, un 206 Partial Content de un único rango, una respuesta 206 multipart/byteranges para varios rangos, o un 416 Range Not Satisfiable.

FirstPageProber es el lado de la prueba estructural: cuantifica el prefijo de la primera página, la fracción de todo el archivo que representa ese prefijo, y si el flujo de pistas primario se encuentra por completo dentro de él, la propiedad que permite a un lector localizar los objetos de la página 1 solo a partir del prefijo.

Webview nunca reanaliza la linealización por sí mismo. Toma prestado el LinearizationView del lado de lectura de Core, de modo que la capa de entrega hereda un único analizador auditado en lugar de una segunda copia que va divergiendo. La construcción es deliberadamente total. LinearizedDocument::fromBytes() rechaza de entrada una disposición mal formada, de modo que todo desplazamiento en el que confía una respuesta Range fue validado primero. El responder habla únicamente PSR-7 y PSR-17, de modo que el mismo código sirve un PDF linealizado desde cualquier pila HTTP. Esa disciplina es lo que hace seguro exponer la entrega progresiva por rangos a clientes no confiables a gran volumen.

Contexto de diseño: Generación de documentos de alto volumen.

Cómo funciona el servicio progresivo por rango de bytes

Sección titulada «Cómo funciona el servicio progresivo por rango de bytes»
  1. Construya un LinearizedDocument a partir de los bytes del PDF renderizado. Una entrada no válida provoca UnsupportedDocumentException de entrada.
  2. Entregue el documento y el ServerRequestInterface PSR-7 entrante a ByteRangeResponder::respond(). El responder lee Range (y la precondición opcional If-Range) y produce el ResponseInterface PSR-7 correcto.
  3. El cliente solicita primero el prefijo inicial (o usted lo envía mediante firstPageResponse()), renderiza la página 1 y luego solicita los rangos restantes a medida que el usuario se desplaza.

El modelo de rango de bytes usa desplazamientos inclusivos según RFC 9110 §14.1.2: un ByteRange es firstBytelastByte sobre una representación de contentLength, y su campo Content-Range es bytes first-last/length.

  • LinearizedDocument::fromBytes() es total: un documento no linealizado, una discrepancia de /L o un desplazamiento /E no positivo / fuera del archivo provocan, cada uno, UnsupportedDocumentException en lugar de producir un documento inseguro.
  • El ETag es una etiqueta de entidad SHA-256 fuerte sobre los bytes exactos, memoizada una sola vez en la construcción. Una entrada de renderizado idéntica produce bytes idénticos y, por tanto, un ETag idéntico, de modo que las cachés y If-Range se comportan de forma predecible.
  • Una solicitud sin ningún Range aplicable devuelve 200 OK con el cuerpo completo. Un If-Range que no coincide con el ETag fuerte actual hace que se ignore el Range y se devuelva un 200 completo (RFC 9110 §13.1.5). Solo se respeta la forma de etiqueta de entidad fuerte de If-Range; un If-Range de fecha HTTP se trata como una no coincidencia.
  • Una unidad de rango no reconocida o un Range sintácticamente no válido se ignora y se devuelve un 200 completo (RFC 9110 §14.2).
  • Un rango satisfacible devuelve 206 Partial Content con Content-Range; varios rangos satisfacibles devuelven 206 multipart/byteranges. Rangos de bytes válidos sin ninguno satisfacible devuelven 416 con Content-Range: bytes */length (RFC 9110 §15.3.7).
  • firstPageResponse() emite un 206 que transporta exactamente el rango de bytes de la primera página [0, /E - 1]: la forma de envío por servidor de «la primera página antes de la descarga completa».

A continuación se refleja la API pública documentada. El repositorio no incluye un ejemplo ejecutable para este módulo.

use NextPDF\Pro\Webview\LinearizedDocument;
use NextPDF\Pro\Webview\ByteRangeResponder;
$document = LinearizedDocument::fromBytes($pdfBytes);
$responder = new ByteRangeResponder($responseFactory, $streamFactory);
$response = $responder->respond($document, $request);

Ejemplo de código — Envío y sondeo de la primera página

Sección titulada «Ejemplo de código — Envío y sondeo de la primera página»
use NextPDF\Pro\Webview\LinearizedDocument;
use NextPDF\Pro\Webview\ByteRangeResponder;
use NextPDF\Pro\Webview\FirstPageProber;
use NextPDF\Pro\Webview\Exception\UnsupportedDocumentException;
try {
$document = LinearizedDocument::fromBytes($pdfBytes);
} catch (UnsupportedDocumentException $e) {
// Not a usable linearized document — fall back to plain full delivery.
// ...
return;
}
$prober = new FirstPageProber($document);
if ($prober->isFirstPageSelfContained()) {
// Push exactly the first page's bytes for an instant render.
$response = (new ByteRangeResponder($responseFactory, $streamFactory))
->firstPageResponse($document);
}
  • Webview requiere un PDF genuinamente linealizado. Si el documento renderizado no está linealizado, habilite la linealización en el momento del renderizado, o sírvalo con entrega completa simple — respondToBytes() todavía puede servir rangos sobre bytes arbitrarios (no linealizados) cuando solo necesita compatibilidad con rangos, no semántica de primera página.
  • Las actualizaciones incrementales importan: un documento al que se anexó más allá de su /L declarado se rechaza como una discrepancia de longitud, porque los desplazamientos de rango de bytes ya no serían confiables.
  • El responder limita el número de rangos distintos que respeta por solicitud. Una solicitud que pide más rangos fusionados que el límite, o más bytes totales que toda la representación, ve ignorado su Range y se le sirve un 200 completo.

El prefijo de la primera página es el desplazamiento /E de fin de primera página recortado a la longitud del archivo, por lo que FirstPageProber::prefixFraction() informa de lo pequeña que es la obtención inicial respecto a todo el archivo — para un documento de muchas páginas, este es todo el sentido de Fast Web View. La construcción de la respuesta corta la cadena de bytes en memoria; el costo es proporcional a los bytes seleccionados. El ETag se calcula una sola vez por documento. Mida con documentos representativos.

Trate la entrada como no confiable. LinearizedDocument::fromBytes() valida las invariantes de linealización antes de usar ningún desplazamiento. El responder rechaza un contentType que contenga caracteres de control para impedir la inyección de cabeceras, deriva un límite multipart que está garantizado que no aparece dentro del cuerpo, y fusiona los rangos solapados y acota su número y tamaño total para defenderse de la clase de denegación de servicio por amplificación de rango multipart (Apache HTTPD CVE-2011-3192). Este módulo no registra ningún contenido del documento.

La entrega por rango de bytes sigue RFC 9110 (HTTP Semantics): §14 para las solicitudes de rango, §13.1.5 para If-Range y §15.3.7 para 416. El modelo de documento linealizado es la disposición Fast Web View descrita por ISO 32000-2 Annex F. El módulo no afirma más identificadores de cláusula externos que el comportamiento verificado por sus pruebas.

Enterprise no cambia el comportamiento de Webview. Enterprise añade funciones de cumplimiento y archivo de nivel superior documentadas por separado; no son necesarias para servir un PDF linealizado por rangos de bytes.

Esta página documenta únicamente el comportamiento observable externamente y la superficie de API pública admitida. Las rutas de espacio de nombres internas, las clases auxiliares, las tablas de mecanismos, los nombres de archivo de runbook y los prefijos de tickets quedan fuera del alcance.