Long-polling in Laravel chat: Why is the div not u

2020-03-30 03:22发布

I'm trying to build a laravel chat app with long-polling (I know there's nodejs/redis but there's a problem) and therefore I have been trying to implement this example into Laravel and MySQL.

However, the AJAX GET status request is always stuck at pending.... I figured this might be the cause that it is not updating the div where I display my new newly inputted value from an AJAX POST request on the same page. Currently, the div only updates itself on refresh.

Here are my codes :

View

function getMsg(timestamp){
    var queryString = {"timestamp":timestamp};
    $.get(
        "create",
        queryString,
        function(data){
            var obj = $.parseJSON(data);
            console.log(obj.timestamp);
            $('#response').append('<p>'+obj.body+'</p>');
            getMsg(obj.timestamp);
        }
    ).fail( function(xhr, textStatus, errorThrown) {
            alert(xhr.responseText);
        });
}
getMsg();

Controller

public function create()
{
    $Msg = new Chatting;
    if(Request::ajax()){
        set_time_limit(0);
        session_write_close();
        while(true){

            $last_ajax_call = isset($_GET['timestamp'])?(int)$_GET['timestamp']:null;

            clearstatcache();
            $last_timestamp = $Msg->select(array('created_at'))->orderBy('created_at','desc')->first();
            $last_change = json_decode($last_timestamp);
            if($last_ajax_call == null || $last_change->created_at > $last_ajax_call){
                $result = array(
                    'body'=> $Msg->select('body','created_at')->where('created_at','=',$last_change->created_at)->first()->body,
                    'timestamp'=> $last_change->created_at
                );
                $json = json_encode($result);
                echo $json;
                break;
            }else{
                sleep(1);
            }
        }

    }else{
        $msgdata = $Msg->select(array('created_at','body'))->orderBy('created_at','asc')->get();
        return View::make('brightcms.Chatting.Chatting',compact('msgdata'));
    }
}

GET Request Header

Request URL:http://localhost/msgsys/public/cms/Chatting/create?timestamp=2014-06-09+06%3A49%3A11
Request Headers CAUTION: Provisional headers are shown.
Accept:*/*
Cache-Control:no-cache
Pragma:no-cache
Referer:http://localhost/msgsys/public/cms/Chatting/create
Chrome/35.0.1916.114 Safari/537.36
X-Requested-With:XMLHttpRequest
Query String Parametersview sourceview URL encoded
timestamp:2014-06-09 06:49:11

Btw, bonus points for best ways to :

  1. Improve the code so that it makes the most out of Laravel 4's functions and ways of doing stuff.
  2. Run NodeJS on dreamhost/shared server without any restriction. Currently, there's this problem.

So yeah, how do I fix my code so that when I input a new value, the app will update a div to display the newly inputted value like a real-time app?

I'm still quite new in Laravel and would appreciate criticisms/advises. Thank you very much!

1条回答
干净又极端
2楼-- · 2020-03-30 03:33

From what I see, I think infinite while loop is the problem here.

PHP and Sockets

If you cannot use NodeJS, try out PHP with Sockets. Should work for this pretty well!

Improvements

You said you search for improvements. Here they are.
Plus I would use Angular to bind data retrieved from server to the view.

The view file

<html>
    <head>
        <title></title>
        {{ HTML::script('//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.1/jquery.min.js') }}
        <style>
            #chat {
                width: 300px;
            }
            #input {
                border: 1px solid #ccc;
                width: 100%;
                height: 30px;
            }
            #messages {
                padding-top: 5px;
            }
            #messages > div {
                background: #eee;
                padding: 10px;
                margin-bottom: 5px;
                border-radius: 4px;
            }
        </style>
    </head>
    <body>
        <div id="chat">
            <input id="input" type="text" name="message" value="">
            <div id="messages">
            </div>
        </div>

        <script>
            var $messagesWrapper = $('#messages');

            // Append message to the wrapper,
            // which holds the conversation.
            var appendMessage = function(data) {
                var message = document.createElement('div');
                message.innerHTML = data.body;
                message.dataset.created_at = data.created_at;
                $messagesWrapper.append(message);
            };

            // Load messages from the server.
            // After request is completed, queue
            // another call
            var updateMessages = function() {
                var lastMessage = $messagesWrapper.find('> div:last-child')[0];
                $.ajax({
                    type: "POST",
                    url: '{{ url('chat/refresh') }}',
                    data: {
                        from: ! lastMessage ? '' : lastMessage.dataset.created_at
                    },
                    success: function(messages) {
                        $.each(messages, function() {
                            appendMessage(this);
                        });
                    },
                    error: function() {
                        console.log('Ooops, something happened!');
                    },
                    complete: function() {
                        window.setTimeout(updateMessages, 2000);
                    },
                    dataType: 'json'
                });
            };

            // Send message to server.
            // Server returns this message and message
            // is appended to the conversation.
            var sendMessage = function(input) {
                if (input.value.trim() === '') { return; }

                input.disabled = true;
                $.ajax({
                    type: "POST",
                    url: '{{ url('/chat') }}',
                    data: { message: input.value },
                    success: function(message) {
                        appendMessage(message);
                    },
                    error: function() {
                        alert('Ooops, something happened!');
                    },
                    complete: function() {
                        input.value = '';
                        input.disabled = false;
                    },
                    dataType: 'json'
                });
            };

            // Send message to the servet on enter
            $('#input').on('keypress', function(e) {
                // Enter is pressed
                if (e.charCode === 13) {
                    e.preventDefault();
                    sendMessage(this);
                }
            });

            // Start loop which get messages from server.
            updateMessages();
        </script>
    </body>
</html>

Routes

Route::post('chat/refresh', function() {
    $from = Input::get('from', null);

    if (is_null($from)) {
        $messages = Message::take(10);
    } else {
        $messages = Message::where('created_at', '>', $from);
    }

    return $messages->latest()->get();
});

Route::post('chat', function() {
    return Message::create(['body' => Input::get('message')]);
});

Route::get('chat', function() {
    return View::make('chat');
});

Model

class Message extends Eloquent
{

    protected $fillable = ['body'];
}

I think, code is pretty straighforward... Comments should explain everything.

查看更多
登录 后发表回答