2013-08-23 1 views
7
나는 초와 클라이언트에 연결을 종료하고 있습니다

: PHP는 연결을 일찍 닫습니다. 모든 출력이 완료되면 스크립트는 중단

static public function early_close($output) 
{ 
    ignore_user_abort(true); 
    echo $output; 

    // Disable gzip compression in apache, as it can result in this request being buffered until it is complete, 
    // regardless of other settings. 
    if (function_exists('apache_setenv')) { 
     apache_setenv('no-gzip', 1); 
    } 

    // get the size of the output 
    $size = ob_get_length(); 

    // send headers to tell the browser to close the connection 
    header("Content-Length: $size"); 
    header('Connection: close'); 
    header("Content-Encoding: none"); // To disable Apache compressing anything 

    // IF PHP-FM 
    // fastcgi_finish_request(); 

    // flush all output 
    if(ob_get_level() > 0) 
    { 
     ob_end_flush(); 
     ob_get_level()? ob_flush():null; 
     flush(); 
    } 

    // if you're using sessions, this prevents subsequent requests 
    // from hanging while the background process executes 
    if(session_id()) 
    { 
     session_write_close(); 
    } 
} 

작품 좋아,하지만이 사건 후 일부 스크립트는 echo'ing 또는 추가하여 하나 (아무것도 출력하는 경우 새 헤더) 스크립트는 해당 지점에서 실행을 중지합니다.
일찍 마감 후 출력 버퍼링을 시작 시도하고 다음을 폐기했지만 작동하지 않습니다

Server::early_close(); 
ob_start(); 
heavy_work(); 
ob_clean(); 

어떤 아이디어?
PHP 5.3.x

+0

간단한 'die()'버릇이 있습니까? – Anthony

+0

'die()'는 여기서 도움이되지 않습니다. 왜냐하면 서버가'heavy_work' 명령을 받자 마자 클라이언트가 응답해야하기 때문입니다. 클라이언트는 끝내기 위해'heavy_work'를 기다릴 필요가 없습니다. 'Server :: early_close() '대신에'die()'가 실행되면'heavy_work()'가 실행되지 않습니다. –

+0

HTTP 응답이 끝나면 _webserver_ 스레드를 계속 실행하지 마십시오.비동기 작업으로 만듭니다. 기어 맨 (Gearman) 등이 당신을 위해 많은 세부 사항을 처리 할 수 ​​있지만 모든 작업 (대기열)이 수행합니다. – Wrikken

답변

3

그 작업을 수행하는 고전적인 코드는 다음과 같습니다

ob_end_clean(); 
header("Connection: close"); 
ignore_user_abort();    // optional ob_start(); 

echo ('Text the user will see'); 

$size = ob_get_length(); 
header("Content-Length: $size"); 
ob_end_flush();     // Strange behaviour, will not work 
flush();       // Unless both are called ! 

// Do processing here 
sleep(30); 

echo('Text user will never see'); 

그렇지 않으면, 당신은 비동기 호출을 수행하려는 경우 나는 다음 읽기를 제안한다 : 현재까지 귀하의 의견을 바탕으로

+0

연결이 제대로 닫히기 때문에 스크립트가 실행을 멈추고 스크립트가 실행되는 것을 막을 수 있습니다. –

+0

출력 결과가 확실합니까? 타임 아웃/메모리 제한/등은 없습니까? – Toto

+0

예, 에코를 "무거운 작업"안에 배치하면 실행이 끝나지 않고 에코가 실행되는 동일한 줄에서 멈 춥니 다. 이 에코가 주석 처리되면 스크립트가 성공적으로 끝납니다. –

2

IMHO를 사용하면 안됩니다. 유용성을 높이려면 Http 요청을 최대한 짧게해야합니다.

"무거운 처리"를 수행해야하는 경우 대기열을 사용하여 일정을 조정할 수 있습니다. 서버의 별도 프로세스/데몬은 대기열에서 이러한 작업을 선택하여 수행 할 수 있습니다. 그런 다음 http 응용 프로그램은 해당 작업이 여전히 처리 대기 중이거나 시작되었거나 완료되었는지 확인할 수 있습니다.

많은 도서관이 용이 할 수 있습니다 Gearman, ØMQ, RabbitMQ 등의 요청이 정말로하려고 할 때 모든 종류의 문제로 실행하는 이유입니다, 오랜 작업에 적합하지 않은 HTTP를

그래서 :)

UPDATE

서버에 (Gearman을 등처럼), 당신은에 자신의 파일 - 또는 DB 기반 큐, 푸시는 "명령"을 만들 수 라이브러리를 사용할 수없는 경우 ~로부터의 큐 귀하의 응용 프로그램에서 cronjob이 대기열을 읽고 그러한 작업을 수행하도록하십시오.

+0

그 이유는 가능한 한 빨리 연결을 닫는 것입니다. –

+1

원하는 작업을 수행하기 위해 프로세스가 계속 실행되고 있다는 사실에 의존하고 있지만이 작업이 성공할 것이라고 보장 할 방법이 없으며 실패를보고하지 못합니다. 사용자. –

+0

+1 백그라운드 작업 솔루션 (심지어 직접 롤업 구현)을 사용하는 것은 고의적 인 HTTP 요청에 의존하는 것이 오산하지 않고 더 좋은 아이디어이며보다 강력합니다. – AD7six

1

echo chr (0); echo $ 출력 후; null 바이트를 보내면 브라우저가 강제로 연결을 종료합니다. 또한, 나는 Server :: early_close() 전에 ob_start()가 있다고 가정합니다. 그렇지 않다면 ob_get_length가 제대로 작동하도록해야합니다.

+0

예,'ob_start()'호출이 있습니다. –

1

Methods for asynchronous processes in PHP, 당신의 교체 추천을 페이지로드시 AJAX 요청이있는 현재 솔루션 연결을 일찍 종료하고 서버에서 계속 처리하는 대신 일반적으로 응답을 제공하고 페이지가 클라이언트에로드 된 후 AJAX 요청을 추가하여 추가 처리를 추가하십시오. 이로 인해 관련없는 출력 문제가 완전히 제거되고 모든 성공/실패 메시지를 다시 사용자에게 보낼 수 있습니다.

다른 해결책은 테이블이나 메모리에 작업을 대기시키고 배경에서 처리 할 cron을 설정하는 것입니다.

+0

이 스크립트는 이미 ajax 호출을 통해 요청되었습니다. 내가 찾은 것은 초기 닫기가 설정되지 않은 경우 요청 시간이 초과되었다는 것입니다. –

+0

아, 그럴 경우 시간 초과를 연장하고 연결을 일찍 닫을 수 없습니다. 비록 오래 실행중인 백그라운드 프로세스가 있다면 나는 cron 대신에 (긴 timeout으로) 매우 좋습니다. –

관련 문제