walkor / workerman

An asynchronous event driven PHP socket framework. Supports HTTP, Websocket, SSL and other custom protocols.
http://www.workerman.net
MIT License
11.17k stars 2.27k forks source link

Connection close or set NULL using Request connection #1034

Closed uribes78 closed 6 months ago

uribes78 commented 6 months ago

Hi, I'm developing a web service using th HTTP protocol and want to send a file using chunks

My code is:

$req->connection->send( (new Response(200, [
                                    'Transfer-Encoding' => 'chunked',
                                    'Content-Description' => 'File Transfer',
                                    'Content-Type' => 'application/octet-stream',
                                    'Pragma' => 'public',
                                    "Content-Disposition" => "attachment; filename=\"{$filename}\""
                                ], 'follow')) );

        error_log(__METHOD__.": [AFTER] Request connection state -> ".print_r($req->connection, 1)); //here I'm getting a null

        $callback = function ($row) use ($req) {
            $req->connection->send( new Chunk( implode(',', (array) $row) ) );
        };

        $result = $bo->{$report}(QueryRequest::getInstance($req), $callback);

but when a callback is executed and try to use the connection inside request I getting this error:

Worker[28498] process terminated with ERROR: E_ERROR "Call to a member function send() on a non-object

Am I doing something wrong? How can I send chunked part of a file (creating a CSV comming from database)

Hope you can give a glance! thanks.

walkor commented 6 months ago

The connection property of the $req will be deleted after the send() call. So you can store connection to a variable. Codes like this.

$connection = $req->connection;
$connection->send( (new Response(200, ...);
$callback = function ($row) use ($connection) {
      $connection->send( new Chunk( implode(',', (array) $row) ) );
};
uribes78 commented 6 months ago

Great, changing as you suggest it works that part. But I'm facing this, once the process sending chunk's has finished, I doing this:

        $callback = function ($row) use ($connection) {
            $connection->send( new Chunk( implode(',', (array) $row) ) );
        };

        $result = $bo->{$report}(QueryRequest::getInstance($req), $callback);

        return (new Response(200))->withBody( new Chunk('') );

But, the browser is detecting a failed and abort the download, as you can see in this image:

imagen

the return line could be the problem?, I'm doing this, because I need to return a Response object beacuse it's on middleware flow, and the last middleware expect to get a Response object to send the last result

Any suggestion? Thanks

uribes78 commented 6 months ago

Well, I solved it, just changed like this:

        $callback = function ($row) use ($connection) {
            $connection->send( new Chunk( implode(',', (array) $row)."\n" ) );
        };

        $result = $bo->{$report}(QueryRequest::getInstance($req), $callback);
        $connection->send( new Chunk('') );

        return new Response(200);

Thanks anyway! Workerman it's a great framework.