XMLHttpRequest에서 진행하는 방법


133

XMLHttpRequest (업로드 된 바이트, 다운로드 된 바이트)의 진행률을 얻을 수 있습니까?

사용자가 큰 파일을 업로드 할 때 진행률 표시 줄을 표시하는 데 유용합니다. 표준 API는 그것을 지원하지 않는 것 같지만, 어떤 브라우저에도 비표준 확장이 있습니까? 클라이언트가 업로드 / 다운로드 한 바이트 수를 알고 있기 때문에 결국에는 매우 분명한 기능인 것 같습니다.

참고 : 나는 "진행을 위해 서버 설문 조사"대안을 알고 있습니다 (지금 내가하고있는 일입니다). 이 문제의 주된 문제점 (복잡한 서버 측 코드 제외)은 일반적으로 큰 파일을 업로드하는 동안 대부분의 ISP가 열악한 업스트림을 제공하기 때문에 사용자의 연결이 완전히 제한된다는 것입니다. 따라서 추가 요청을하는 것은 내가 바라는 것처럼 반응하지 않습니다. 브라우저가 항상 가지고있는이 정보를 얻는 방법 (표준이 아닐 수도 있음)이 있기를 바랐습니다.

답변:


137

업로드 된 바이트의 경우 매우 쉽습니다. xhr.upload.onprogress이벤트를 모니터링하십시오 . 브라우저는 업로드해야하는 파일의 크기와 업로드 된 데이터의 크기를 알고 있으므로 진행 정보를 제공 할 수 있습니다.

다운로드 한 바이트의 경우 (로 정보를 가져올 때 xhr.responseText) 브라우저가 서버 요청에서 몇 바이트를 전송할지 알 수 없기 때문에 조금 더 어렵습니다. 이 경우 브라우저가 아는 유일한 것은 수신하는 바이트의 크기입니다.

이에 대한 해결책이 Content-Length있습니다. 브라우저가받을 바이트의 총 크기를 얻으려면 서버 스크립트에 헤더 를 설정하는 것으로 충분합니다 .

자세한 내용은 https://developer.mozilla.org/en/Using_XMLHttpRequest 로 이동 하십시오 .

예 : 서버 스크립트가 zip 파일을 읽습니다 (5 초 소요).

$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;

이제 총 길이를 알고 있기 때문에 서버 스크립트의 다운로드 프로세스를 모니터링 할 수 있습니다.

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(); 
}

29
"Content-Length"는 예상 길이가 아니며, 정확한 길이, 너무 짧아야하고 브라우저가 다운로드를 너무 길게 차단하고 다운로드가 완료되지 않은 것으로 가정합니다.
Chris Chilvers

@ChrisChilvers PHP 파일이 올바르게 계산되지 않을 수 있다는 의미입니까?
Hydroper

1
이 예제에서 @nicematt는 파일에서 오는 것이 좋을 것입니다.하지만 메모리에서 zip을 바로 스트리밍하는 경우 콘텐츠 길이를 구성하거나 추정 할 수 없었습니다.
Chris Chilvers

3
@TheProHands .php 페이지를 방문하면 서버가 PHP 파일을 실행하고 출력을 보냅니다 . 서버는 .php 파일이 아닌 출력 길이를 보내야합니다.
leewz

누군가 "$ ( '# progressbar'). progressbar ("option ","value ", percentComplete);"줄을 설명해 주시겠습니까? 방법? 특정 플러그인을 호출합니까? 어떻게 작동합니까? 새로운 사용자가 답을 이해할 수 있도록하십시오.
Zac


8

가장 유망한 접근법 중 하나는 서버로 다시 두 번째 통신 채널을 열어서 얼마나 많은 전송이 완료되었는지 묻는 것 같습니다.


24
링크가 죽었을 수도 있습니다
Ronnie Royston


5

전체 업로드의 경우 처리 방법이없는 것 같지만 다운로드하려는 것과 비슷한 것이 있습니다. readyState가 3이면, responseText를 주기적으로 쿼리하여 String으로 다운로드 한 모든 컨텐츠를 얻을 수 있습니다 (IE에서는 작동하지 않음). 모든 시점에서 readyState 4로 전환 될 때까지 모든 컨텐츠를 사용할 수 있습니다. 주어진 시간에 다운로드 된 바이트는 responseText에 저장된 문자열의 총 바이트와 같습니다.

업로드 질문에 대한 전체 또는 전혀 접근 방식의 경우, 업로드를 위해 문자열을 전달해야하기 때문에 readyState 0 및 1에 전송 된 총 바이트는 0이되고 readyState에 대한 총계는 2는 전달한 문자열의 총 바이트입니다. readyState 3 및 4에서 보내고받은 총 바이트는 원래 문자열의 바이트와 responseText의 총 바이트를 합한 것입니다.


3

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

결과


2

Apache 설치 및 신뢰 타사 코드에 액세스 할 수있는 경우 Apache 업로드 진행률 모듈 을 사용할 수 있습니다 (apache를 사용하는 경우 nginx 업로드 진행률 모듈도 있음 ).

그렇지 않으면 파일 상태를 요청하기 위해 대역 외에서 벗어날 수있는 스크립트를 작성해야합니다 (예를 들어 tmp 파일의 파일 크기 확인).

파이어 폭스 3에서 진행중인 작업이 있습니다. 브라우저에 업로드 진행 지원을 추가한다고 생각하지만 모든 브라우저에 들어가서 한동안 널리 채택되지는 않습니다 (더 이상 불쌍합니다).


-7

순수한 자바 스크립트로 그렇게하는 유일한 방법은 일종의 폴링 메커니즘을 구현하는 것입니다. 서버가 수신 한 바이트 수를 얻으려면 고정 간격 (예 : 각 5 초)으로 ajax 요청을 보내야합니다.

보다 효율적인 방법은 플래시를 사용하는 것입니다. flex 구성 요소 FileReference 는 이미 업로드 된 바이트 수를 보유하는 'progress'이벤트를 주기적으로 전달합니다. 자바 스크립트를 고수해야하는 경우 액션 스크립트와 자바 스크립트간에 브리지를 사용할 수 있습니다. 좋은 소식은이 작업이 이미 완료된 것입니다. :)

swfupload

이 라이브러리를 사용하면 플래시 진행률 이벤트에 자바 스크립트 핸들러를 등록 할 수 있습니다.

이 솔루션은 서버 측에 추가 리소스가 필요하지 않다는 큰 장점이 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.