2012-05-09 13 views
17

Tengo un requisito inusual. Básicamente, necesito una forma para que, cuando el usuario haga clic en un enlace o botón, reciba un PDF. La parte difícil aquí es que el servidor no procesará la solicitud en total a menos que se envíe un encabezado personalizado (de lo contrario, considera que la persona se desconectó y lo envía a la pantalla de inicio de sesión).Solicitar un archivo con un encabezado personalizado

En este momento, la forma en que funciona el encabezado no se puede cambiar, así que no se preocupe por ello; Cambiará en el futuro y es una aplicación interna sobre la que no tengo control.

Las opciones que han explorado:

  • El uso de un iframe o simplemente abrir una nueva ventana con algún tipo de ruta que devolverá el PDF. Esto no puede funcionar porque no puedo especificar el encabezado requerido para el PDF y sería redirigido antes de llegar al PDF.
  • El uso de un formulario y el envío de la solicitud no pueden funcionar porque no puedo agregar encabezados personalizados a los formularios (solo XHR y los complementos pueden, AFAIK).
  • El uso de XHR no puede funcionar porque, si bien puede agregar el encabezado y recuperar el archivo, no hay forma de guardarlo en el lado del cliente.

Al parecer, mis únicas opciones en este punto son esencialmente:

  • utilizar algún tipo de plug-in como Flash o Silverlight para solicitar el archivo.
  • Fuerce el cambio del requisito mucho antes de lo esperado para que ya no se requiera un encabezado.

¿Hay algo que me falta aquí? Espero que alguien pueda verificar mis hallazgos o señalarme algo que eché de menos porque, por lo que puedo ver, no hay nada que pueda hacer aquí.

EDIT: Esto parece apto y confirma lo que estaba pensando: XMLHttpRequest to open PDF in browser

+2

¿Qué tal si agregas algún tipo de túnel entre la aplicación y tu script? El túnel podría consultar la aplicación y recibir el archivo, y luego establecer un encabezado adecuado antes de enjuagar el archivo para el usuario, lo que realmente desencadena una descarga. No sé si esto es posible para su sistema, dependiendo de la seguridad. –

+0

Un túnel no es una mala idea, aunque no estoy seguro de que podamos implementarlo aquí. Hmm. Gracias, lo investigaré. – Kris

+1

Si puede prescindir de soporte para IE <10 (no es muy probable, ¿no?), Podría usar XMLHttpRequest Nivel 2 (XHR2) y Blob URL. Aquí hay un ejemplo: http://stackoverflow.com/q/9620497 Vea también http://stackoverflow.com/q/6165266 y http://www.html5rocks.com/en/tutorials/file/xhr2/ –

Respuesta

13

probado para trabajar en cromo:

function toBinaryString(data) { 
    var ret = []; 
    var len = data.length; 
    var byte; 
    for (var i = 0; i < len; i++) { 
     byte=(data.charCodeAt(i) & 0xFF)>>> 0; 
     ret.push(String.fromCharCode(byte)); 
    } 

    return ret.join(''); 
} 


var xhr = new XMLHttpRequest; 

xhr.open("GET", "/test.pdf"); //I had test.pdf this on my local server 


xhr.addEventListener("load", function(){ 
    var data = toBinaryString(this.responseText); 
    data = "data:application/pdf;base64,"+btoa(data); 
    document.location = data; 
}, false); 

xhr.setRequestHeader("magic", "header"); 
xhr.overrideMimeType("application/octet-stream; charset=x-user-defined;"); 
xhr.send(null); 

Puede cambiar application/pdf a application/octet-stream tener aviso de descarga. Pero también es bastante fácil de descargar del lector de Chrome.

En Firefox no pasa nada, supongo que es porque no tengo un complemento para tratar con application/pdf instalado.Al cambiar a application/octet-stream aparecerá un dl.

Con IE supongo que necesita algún tipo de hackery VBScript/ActiveX

Si el archivo es enorme, utilizando URI de datos puede colgarse el navegador, en ese caso se puede utilizar BlobBuilder y objetos de la URL.

+1

¿Es posible poner un nombre de archivo personalizado para la descarga? –

2

lugar de vincular al archivo .PDF, en vez de hacer algo como

<a href="pdf_server.php?file=pdffilename">Download my eBook</a> 

que emite una cabecera personalizada, se abre el PDF (binario seguro) e imprime los datos en el navegador del usuario, luego pueden optar por guardar el PDF a pesar de la configuración de su navegador. El pdf_server.php debería tener este aspecto:

header("Content-Type: application/octet-stream"); 

$file = $_GET["file"] .".pdf"; 
header("Content-Disposition: attachment; filename=" . urlencode($file)); 
header("Content-Type: application/force-download"); 
header("Content-Type: application/octet-stream"); 
header("Content-Type: application/download"); 
header("Content-Description: File Transfer");    
header("Content-Length: " . filesize($file)); 
flush(); // this doesn't really matter. 
$fp = fopen($file, "r"); 
while (!feof($fp)) 
{ 
    echo fread($fp, 65536); 
    flush(); // this is essential for large downloads 
} 
fclose($fp); 

EDIT: La única manera de añadir cabeceras a una solicitud desde el interior de un navegador (del lado del cliente) es utilizar el método XmlHttpRequest setRequestHeader.

xhr.setRequestHeader('custom-header', 'value'); 
+0

Esto fue esencialmente mi primer pensamiento, sin embargo, el encabezado debe agregarse al lado del cliente ya que el servidor simplemente no procesará nada sin dicho encabezado. Entonces, a menos que use algo entre mi cliente y la arquitectura del servidor actual, no se ejecutará nada del lado del servidor. – Kris

+0

No debería tener que agregar el encabezado del lado del cliente. Esto debería funcionar siempre y cuando no haya absolutamente ningún texto antes del encabezado en el archivo php. –

+0

Creo que malinterpretaste mi requerimiento. El servidor que genera el PDF requiere que se envíe un encabezado personalizado junto con todas las solicitudes. Si no se envía el encabezado, se supone que el usuario ha cerrado la sesión, no se ejecuta el código del lado del servidor y la persona se redirige a la pantalla de inicio de sesión. Intento confirmar mis hallazgos, ya que creo que estoy increíblemente limitado a la hora de demostrar una buena solución. – Kris

Cuestiones relacionadas