206 Contenuto parziale restituito con Content-Length: 0

Sto servendo grandi file audio su un server Apache usando mod_xsendfile (versione >= 0.10 ). I file vengono distribuiti bene quando utilizzo l' header( 'HTTP/1.1 200 OK' ); Tuttavia, questi file sono serviti in pieno. Poiché voglio permettere ai visitatori di cercare nei file audio, accetto le richieste di Range dai clienti.

Questo è where ho problemi. Quando utilizzo l' header( 'HTTP/1.1 206 Partial Content' ); , lo script PHP risponde con Content-Length: 0 . Questo è strano a me, perché nella risposta Content-Range , l'intervallo della richiesta e la dimensione totale del file sono menzionati correttamente. Per esempio:

 Content-Length:0 Content-Range:bytes 0-139143856/139143857 

Le intestazioni utilizzate dal mio script PHP per submit queste due intestazioni sono:

 $filesize = filesize( $mix_file ); ... $start = calculated from HTTP_RANGE or 0; $end = calculated from HTTP_RANGE or $filesize - 1; ... header( 'Content-Length: ' . ( ( $end - $start ) + 1 ) ); header( 'Content-Range: bytes ' . $start . '-' . $end . '/' . $filesize ); 

L'intestazione Content-Range viene inviata solo se c'è una richiesta di Range , altrimenti il ​​mio script ignora questa intestazione.

Perché Return Content-Length restituisce 0 quando ho impostato esplicitamente il suo valore?

Le cose che ho provato per la risoluzione dei problemi

  • Carica stream.php?id=9966 con una richiesta di Range , che è la configuration prevista. Script restituisce 206 Partial Content quattro volte (vedi schermata e script previsto in basso). Tutti hanno il Content-Length impostato in modo errato come 0 .
  • Carica stream.php?id=9966 direttamente nel browser. Causa GET di essere inviato senza una richiesta di Range . Script restituisce 200 OK con l'integer contenuto del file. Content-Length viene restituito correttamente . Il file inizia a scaricare nella window del browser.
  • Non impostare l'intestazione del 206 Partial Content nello script in caso di richiesta di Range . Causa script per restituire 200 OK intestazione 200 OK . Content-Length viene restituito correttamente , così come Content-Range .
  • Forza stream.php per restituire sempre 200 OK , anche quando restituisce una risposta di Content-Range . Quando GET ting con una richiesta Range , entrambi i Content-Length e Content-Range vengono restituiti correttamente .
  • Le due configurazioni precedenti non consentono di cercare una posizione non bufferizzata nell'audio, che è un requisito. In entrambi i casi di prova, il contenuto del file viene inviato nella sua interezza e qualsiasi tentativo di ricercare una posizione non tampone provocherebbe l'audio a tagliare fino a quando il download del file non ha "raggiunto".

206 intestazioni restituite

Richiesta

 GET /stream.php?id=9966 HTTP/1.1 Host: next.tjoonz.com Connection: keep-alive Pragma: no-cache Cache-Control: no-cache Accept-Encoding: identity;q=1, *;q=0 User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.134 Safari/537.36 Accept: */* Referer: http://next.tjoonz.com/ Accept-Language: en-US,en;q=0.8,nl;q=0.6 Cookie: __cfduid=d2623ed31d1d855be05395a7fbcf76c311425543933; __uvt=; uvts=3EmUJ804REmm3E0w; wp-settings-1=hidetb%3D1%26editor%3Dhtml%26m10%3Dc%26m8%3Dc%26m5%3Dc%26m0%3Dc%26m9%3Dc%26m6%3Dc%26m3%3Dc%26imgsize%3Dmedium%26align%3Dnone%26m1%3Dc%26m2%3Dc%26m4%3Dc%26m11%3Dc%26m7%3Dc%26wplink%3D1%26urlbutton%3Dfile%26libraryContent%3Dbrowse%26ed_size%3D373%26dfw_width%3D822; wp-settings-time-1=1435585363; _ga=GA1.2.1985480703.1425543937; audio=yes Range: bytes=0- 

Risposta

 HTTP/1.1 206 Partial Content Date: Tue, 14 Jul 2015 18:39:52 GMT Server: Apache Content-Disposition: attachment; filename="sea-monkey-napcast-018.mp3" Accept-Ranges: bytes X-SENDFILE: /home/tjoonzvps/audio/sea-monkey-napcast-018.mp3 Set-Cookie: audio=yes; expires=Wed, 15-Jul-2015 18:39:52 GMT; path=/ Content-Length: 0 Content-Range: bytes 0-145036217/145036218 Keep-Alive: timeout=2, max=97 Connection: Keep-Alive Content-Type: audio/mpeg 

Script PHP (la parte rilevante)

 if( file_exists( $mix_file ) ) { tjnz_increment_plays( $mix_id ); // get the 'Range' header if one was sent if( isset( $_SERVER[ 'HTTP_RANGE' ] ) ) { $range = $_SERVER[ 'HTTP_RANGE' ]; } else { $range = false; } // get the data range requested (if any) $filesize = filesize( $mix_file ); $start = 0; $end = $filesize - 1; if( $range ) { $partial = true; list( $param, $range ) = explode( '=', $range ); if( strtolower( trim( $param ) ) != 'bytes') { header( 'HTTP/1.1 400 Invalid Request' ); die(); } $range = explode( ',', $range ); $range = explode( '-', $range[ 0 ] ); if( count( $range ) != 2 ) { header( 'HTTP/1.1 400 Invalid Request' ); die(); } if ( $range[ 0 ] === '' ) { $end = $filesize - 1; $start = $end - intval( $range[ 0 ] ); } else if( $range[ 1 ] === '' ) { $start = intval( $range[ 0 ] ); $end = $filesize - 1; } else { $start = intval( $range[ 0 ] ); $end = intval( $range[ 1 ] ); if( $end >= $filesize || ( !$start && ( !$end || $end == ( $filesize - 1 ) ) ) ) { $partial = false; } } } else { $partial = false; } // send standard headers header( 'Content-Type: audio/mpeg' ); header( 'Content-Length: ' . ( ( $end - $start ) + 1 ) ); header( 'Content-Disposition: attachment; filename="' . $mix_slug . '.mp3"' ); header( 'Accept-Ranges: bytes' ); // if requested, send extra headers and part of file... if ( $partial ) { header( 'HTTP/1.1 206 Partial Content' ); header( 'Content-Range: bytes ' . $start . '-' . $end . '/' . $filesize ); header( 'X-SENDFILE: ' . $mix_file ); } else { header( 'X-SENDFILE: ' . $mix_file ); } die(); } 

3 Solutions collect form web for “206 Contenuto parziale restituito con Content-Length: 0”

Una rapida lettura del codice sorgente mod_sendfile rivela che semplicemente non support l'invio di contenuti parziali. Se ottiene una risposta diversa da 200, non invia nulla, quindi il tuo contenuto-lunghezza viene cambiato in 0 e nessun corpo di risposta viene restituito.

È ansible provare a utilizzare X-Accel-Redirect con nginx, che funziona in modo analogo e support contenuti parziali. Basta cambiare "X-Sendfile" in "X-Accel-Redirect" nel tuo codice e utilizzare nginx invece di Apache. Tieni presente che la directory contenente i file statici deve avere una location definita come internal nella configuration nginx. Ciò consente entrambi di abilitare X-Accel-Redirect e serve 404 errori a chiunque tenta di accedere direttamente al file statico.

 location /audio/ { internal; } 

mod_xsendfile funziona perfettamente in questo modo. L'ho appena installato per testare.

 <?php header("X-Sendfile: /tmp/xsftest"); header("Content-Type: application/octet-stream"); header("Content-Disposition: attachment; filename=\"xsftest\""); 

serve file generato da $ seq -f %03.0f 001 100 > /tmp/xsftest

 $ curl -v -H "Range: bytes=100-151" -H -v http://myserver/xsf-test.php > GET /xsf-test.php HTTP/1.1 > User-Agent: curl/7.38.0 > Host: myserver > Accept: */* > Range: bytes=100-151 > < HTTP/1.1 206 Partial Content < Date: Sun, 19 Jul 2015 21:52:43 GMT * Server Apache is not blacklisted < Server: Apache < Content-Disposition: attachment; filename="xsftest" < Last-Modified: Sun, 19 Jul 2015 21:47:01 GMT < ETag: "60981c0-190-51b415c7afad3" < Content-Length: 52 < Content-Range: bytes 100-151/400 < Content-Type: application/octet-stream < 026 027 028 029 030 031 032 033 034 035 036 037 038 $ 

(ho rimosso contenuti sensibili)

Quindi la tua applicazione non cercare nei file non compressi potrebbe essere perché la tua applicazione non lo support, o il formato di file non lo support.

O, come sembra, stai utilizzando un browser sbagliato. Purtroppo. Come per questo rapporto di bug Chrome ha problemi di ricerca in file mp3, che non dispongono del tag di informazioni. Ho cercato di utilizzare lo script php sopra citato per servire un file mp3 scaricato dal tuo sito e seguire html (brutto, ma il lavoro).

 <!html5> <audio src="xsf-test.php" controls autoplay loop> <p>Your browser does not support the <code>audio</code> element </p> </audio> 

Firefox 39 e IE 11 giocano e cercano falsamente. Chrome 43 non lo fa.

FYI, mi sono imbattuto in questo stesso problema e ho trovato questa pagina in una ricerca di Google.

X-SendFile si basa su Apache per gestire le richieste di contenuti parziali. Non è necessario impostare le intestazioni e il codice di risposta in php.

Il problema (che ho condiviso) è che imposta il codice di risposta HTTP, nonché le intestazioni Content-Length e Content-Range nel codice php. La soluzione è di prendere tutto questo fuori. Interrompe il module xsendfile per qualche motivo e finisce con il comportmento descritto (inviando una lunghezza del contenuto 0).

Con tutto ciò rimosso, Apache legge il contenuto corretto del file e genera correttamente queste intestazioni e il codice di risposta (200 o 206) in base all'intestazione della gamma (o alla sua mancanza) fornita nella richiesta del client.

Suggerimenti per Linux e Windows Server, quali Ubuntu, Centos, Apache, Nginx, Debian e argomenti di rete.