2008-09-16 17 views
115

Czy można uzyskać postęp w pliku XMLHttpRequest (przesłano bajty, pobrano bajty)?Jak uzyskać postęp z XMLHttpRequest

Byłoby użyteczne pokazywanie paska postępu, gdy użytkownik przesyła duży plik. Standardowy interfejs API nie obsługuje go, ale może jest jakieś niestandardowe rozszerzenie w dowolnej z przeglądarek? Wydaje się, że jest to całkiem oczywiste, ponieważ klient wie, ile bajtów zostało przesłanych/pobranych.

uwaga: jestem świadomy alternatywy "odpytuj serwer dla postępu" (właśnie to robię teraz). główny problem z tym związany (poza skomplikowanym kodem po stronie serwera) polega na tym, że zazwyczaj podczas przesyłania dużego pliku połączenie użytkownika jest całkowicie zablokowane, ponieważ większość dostawców usług internetowych oferuje słabe środowisko źródłowe. Dlatego składanie dodatkowych próśb nie jest tak szybkie, jak się spodziewałem. Miałem nadzieję, że będzie jakiś sposób (może niestandardowy), aby uzyskać te informacje, które przeglądarka ma zawsze.

Odpowiedz

10

Jest ładny omówienie wskaźnik postępu dla AJAX wzór tutaj:

http://ajaxpatterns.org/Progress_Indicator

Jednym z najbardziej obiecujących rozwiązań wydaje się być otwarcie drugiego kanału komunikacyjnego z powrotem do serwera, aby go zapytać, ile przelew został zakończony.

+7

myślę odnośnikiem może być martwy –

2

Jeśli masz dostęp do instalacji apache i zaufania kodu innej firmy, możesz użyć apache upload progress module (jeśli używasz Apache, jest też nginx upload progress module).

W przeciwnym razie musisz napisać skrypt, który pozwoli ci wyjść poza pasmo, aby zażądać statusu pliku (na przykład sprawdzając rozmiar pliku tmp).

Trochę się dzieje w Firefoksie 3 Wydaje mi się, że mogę dodać obsługę postępu do przeglądarki, ale to nie da się we wszystkich przeglądarkach i zostanie szeroko zaadoptowane na jakiś czas (więcej szkoda).

4

Jeśli chodzi o sumę przesłanych plików, wydaje się, że nie ma na to sposobu, ale jest coś podobnego do tego, co chcesz pobrać. Gdy parametr readyState ma wartość 3, można okresowo wysyłać zapytanie responseText, aby pobrać całą zawartość pobraną do tej pory jako ciąg (to nie działa w IE), aż do momentu, gdy wszystko będzie dostępne, w którym momencie przejdzie do trybu gotowego. bajty pobrane w danym momencie będą równe sumie bajtów w ciągu zapisanym w responseText.

Dla podejścia "wszystko albo nic" w kwestii przesyłania, ponieważ musisz przekazać ciąg do przesłania (i możliwe jest określenie całkowitej liczby bajtów tego), całkowita liczba bajtów wysłanych dla stanu gotowości 0 i 1 będzie wynosić 0, i suma dla readyState 2 będzie całkowitą liczbą bajtów w ciągu, który przekazałeś. Całkowita liczba bajtów wysłanych i odebranych w readyState 3 i 4 będzie sumą bajtów w oryginalnym łańcuchu plus całkowite bajty w tekście odpowiedzi.

-6

Jedynym sposobem, aby to zrobić z czystym javascriptem, jest wdrożenie mechanizmu odpytywania. Będziesz musiał wysłać zapytania ajax w ustalonych odstępach czasu (na przykład co 5 sekund), aby uzyskać liczbę bajtów odebranych przez serwer.

Bardziej skutecznym sposobem byłoby użycie lampy błyskowej. Składnik elastyczny FileReference wysyła okresowo zdarzenie "postępu" zawierające liczbę bajtów już przesłanych. Jeśli chcesz trzymać się JavaScript, dostępne są pomosty między actionscript i javascript. Dobrą wiadomością jest to, że prace zostały już wykonane dla ciebie :)

swfupload

Biblioteka ta umożliwia rejestrację obsługi javascript w przypadku postępu błysk.

Rozwiązanie to ma ogromną zaletę, ponieważ nie wymaga zasobów adnotacji po stronie serwera.

122

Dla przesłanych bajtów jest całkiem łatwa. Wystarczy monitorować wydarzenie xhr.upload.onprogress. Przeglądarka zna rozmiar plików, które ma przesłać oraz rozmiar przesłanych danych, dzięki czemu może podać informacje o postępie.

Dla pobranych bajtów (podczas pobierania informacji z xhr.responseText), jest to nieco trudniejsze, ponieważ przeglądarka nie wie, ile bajtów zostanie wysłanych w żądaniu serwera. Jedyną rzeczą, którą przeglądarka wie w tym przypadku, jest rozmiar odbieranych bajtów.

Istnieje rozwiązanie, wystarczy ustawić nagłówek Content-Length w skrypcie serwera, aby uzyskać całkowity rozmiar bajtów, które przeglądarka ma otrzymać.

Więcej informacji na stronie https://developer.mozilla.org/en/Using_XMLHttpRequest.

Przykład: Mój skrypt serwer odczytuje plik zip (trwa 5 sekund):

$filesize=filesize('test.zip'); 

header("Content-Length: " . $filesize); // set header length 
// if the headers is not set then the evt.loaded will be 0 
readfile('test.zip'); 
exit 0; 

Teraz mogę monitorować proces pobierania skryptu na serwerze, bo wiem, że to długość całkowita:

function updateProgress(evt) 
{ 
    if (evt.lengthComputable) 
    { // evt.loaded the bytes the browser received 
     // evt.total the total bytes set by the header 
     // jQuery UI progress bar to show the progress on screen 
    var percentComplete = (evt.loaded/evt.total) * 100; 
    $('#progressbar').progressbar("option", "value", percentComplete); 
    } 
} 
function sendreq(evt) 
{ 
    var req = new XMLHttpRequest(); 
    $('#progressbar').progressbar();  
    req.onprogress = updateProgress; 
    req.open('GET', 'test.php', true); 
    req.onreadystatechange = function (aEvt) { 
     if (req.readyState == 4) 
     { 
      //run any callback here 
     } 
    }; 
    req.send(); 
} 
+24

Warto zauważyć, „Content-Length” nie jest szacowana długość, musi być dokładna długość, zbyt krótka, a przeglądarka wyłączy pobieranie, zbyt długo i przeglądarka założy, że pobieranie nie zostało zakończone. –

+1

tak, prawda jest szacowana, tylko pomyłka – albanx

+0

@ChrisChilvers Oznacza to, że plik PHP może nie być poprawnie obliczony, prawda? – Hydro

2

<!DOCTYPE html> 
 
<html> 
 
<body> 
 
<p id="demo">result</p> 
 
<button type="button" onclick="get_post_ajax();">Change Content</button> 
 
<script type="text/javascript"> 
 
\t function update_progress(e) 
 
\t { 
 
\t if (e.lengthComputable) 
 
\t { 
 
\t  var percentage = Math.round((e.loaded/e.total)*100); 
 
\t  console.log("percent " + percentage + '%'); 
 
\t } 
 
\t else 
 
\t { 
 
\t \t console.log("Unable to compute progress information since the total size is unknown"); 
 
\t } 
 
\t } 
 
\t function transfer_complete(e){console.log("The transfer is complete.");} 
 
\t function transfer_failed(e){console.log("An error occurred while transferring the file.");} 
 
\t function transfer_canceled(e){console.log("The transfer has been canceled by the user.");} 
 
\t function get_post_ajax() 
 
\t { 
 
\t \t var xhttp; 
 
\t \t if (window.XMLHttpRequest){xhttp = new XMLHttpRequest();}//code for modern browsers} 
 
\t \t else{xhttp = new ActiveXObject("Microsoft.XMLHTTP");}// code for IE6, IE5 \t \t 
 
\t \t xhttp.onprogress = update_progress; 
 
\t \t xhttp.addEventListener("load", transfer_complete, false); 
 
\t \t xhttp.addEventListener("error", transfer_failed, false); 
 
\t \t xhttp.addEventListener("abort", transfer_canceled, false); \t \t 
 
\t \t xhttp.onreadystatechange = function() 
 
\t \t { 
 
\t  \t if (xhttp.readyState == 4 && xhttp.status == 200) 
 
\t  \t { 
 
\t  \t \t document.getElementById("demo").innerHTML = xhttp.responseText; 
 
\t  \t } 
 
\t \t }; 
 
\t xhttp.open("GET", "http://it-tu.com/ajax_test.php", true); 
 
\t xhttp.send(); 
 
\t } 
 
</script> 
 
</body> 
 
</html>

Result