How do I close a connection early?

前端 未结 19 1381
情书的邮戳
情书的邮戳 2020-11-22 04:24

I\'m attempting to do an AJAX call (via JQuery) that will initiate a fairly long process. I\'d like the script to simply send a response indicating that the process has star

相关标签:
19条回答
  • 2020-11-22 05:07

    I'm on a shared host and fastcgi_finish_request is setup to exit scripts completely. I don't like the connection: close solution either. Using it forces a separate connection for subsequent requests, costing additional server resources. I read the Transfer-Encoding: cunked Wikipedia Article and learned that 0\r\n\r\n terminates a response. I haven't thoroughly tested this across browsers versions and devices, but it works on all 4 of my current browsers.

    // Disable automatic compression
    // @ini_set('zlib.output_compression', 'Off');
    // @ini_set('output_buffering', 'Off');
    // @ini_set('output_handler', '');
    // @apache_setenv('no-gzip', 1);
    
    // Chunked Transfer-Encoding & Gzip Content-Encoding
    function ob_chunked_gzhandler($buffer, $phase) {
        if (!headers_sent()) header('Transfer-Encoding: chunked');
        $buffer = ob_gzhandler($buffer, $phase);
        return dechex(strlen($buffer))."\r\n$buffer\r\n";
    }
    
    ob_start('ob_chunked_gzhandler');
    
    // First Chunk
    echo "Hello World";
    ob_flush();
    
    // Second Chunk
    echo ", Grand World";
    ob_flush();
    
    ob_end_clean();
    
    // Terminating Chunk
    echo "\x30\r\n\r\n";
    ob_flush();
    flush();
    
    // Post Processing should not be displayed
    for($i=0; $i<10; $i++) {
        print("Post-Processing");
        sleep(1);
    }
    
    0 讨论(0)
  • 2020-11-22 05:09

    this worked for me

    //avoid apache to kill the php running
    ignore_user_abort(true);
    //start buffer output
    ob_start();
    
    echo "show something to user1";
    //close session file on server side to avoid blocking other requests
    session_write_close();
    
    //send length header
    header("Content-Length: ".ob_get_length());
    header("Connection: close");
    //really send content, can't change the order:
    //1.ob buffer to normal buffer,
    //2.normal buffer to output
    ob_end_flush();
    flush();
    //continue do something on server side
    ob_start();
    //replace it with the background task
    sleep(20);
    
    0 讨论(0)
  • 2020-11-22 05:17

    Complete version:

    ignore_user_abort(true);//avoid apache to kill the php running
    ob_start();//start buffer output
    
    echo "show something to user";
    session_write_close();//close session file on server side to avoid blocking other requests
    
    header("Content-Encoding: none");//send header to avoid the browser side to take content as gzip format
    header("Content-Length: ".ob_get_length());//send length header
    header("Connection: close");//or redirect to some url: header('Location: http://www.google.com');
    ob_end_flush();flush();//really send content, can't change the order:1.ob buffer to normal buffer, 2.normal buffer to output
    
    //continue do something on server side
    ob_start();
    sleep(5);//the user won't wait for the 5 seconds
    echo 'for diyism';//user can't see this
    file_put_contents('/tmp/process.log', ob_get_contents());
    ob_end_clean();
    
    0 讨论(0)
  • 2020-11-22 05:18

    It's necessary to send these 2 headers:

    Connection: close
    Content-Length: n (n = size of output in bytes )
    

    Since you need know the size of your output, you'll need to buffer your output, then flush it to the browser:

    // buffer all upcoming output
    ob_start();
    echo "We'll email you as soon as this is done.";
    
    // 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');
    
    // flush all output
    ob_end_flush();
    ob_flush();
    flush();
    
    // if you're using sessions, this prevents subsequent requests
    // from hanging while the background process executes
    if (session_id()) session_write_close();
    
    /******** background process starts here ********/
    

    Also, if your web server is using automatic gzip compression on the output (ie. Apache with mod_deflate), this won't work because actual size of the output is changed, and the Content-Length is no longer accurate. Disable gzip compression the particular script.

    For more details, visit http://www.zulius.com/how-to/close-browser-connection-continue-execution

    0 讨论(0)
  • 2020-11-22 05:18

    Your problem can be solved by doing some parallel programming in php. I asked a question about it a few weeks ago here: How can one use multi threading in PHP applications

    And got great answers. I liked one in particular very much. The writer made a reference to the Easy Parallel Processing in PHP (Sep 2008; by johnlim) tutorial which can actually solve your problem very well as I have used it already to deal with a similar problem that came up a couple of days ago.

    0 讨论(0)
  • 2020-11-22 05:19

    Latest Working Solution

        // client can see outputs if any
        ignore_user_abort(true);
        ob_start();
        echo "success";
        $buffer_size = ob_get_length();
        session_write_close();
        header("Content-Encoding: none");
        header("Content-Length: $buffer_size");
        header("Connection: close");
        ob_end_flush();
        ob_flush();
        flush();
    
        sleep(2);
        ob_start();
        // client cannot see the result of code below
    
    0 讨论(0)
提交回复
热议问题