如何完全实现服务器发送事件以进行消息轮询

4
我将尝试使用API与服务器进行通信。
为了简化操作,我编写了一个脚本,该脚本将使用php脚本通信API。
我的目标是每秒向API发出查询,以查看其队列中是否有新消息。
建议我使用服务器发送事件方法,并且只有在服务器有新内容时才向客户端发送响应。
以下是我的php脚本。
<?php

    // Register autoloader function
    spl_autoload_register('apiAutoloader');
    header("Content-Type: text/event-stream\n\n");

    $config = array('host' => 'server:IP',              //REQUIRED - Server Name
                    'port' => 8018,                     //REQUIRED - Server Port
                    'userID' => 'user',                 //REQUIRED - UserID to login with
                    'password' => '123456',             //REQUIRED - password for the UserID to login with
                    );

    try {

        //create a new instance of icws
        $icws = new API\ICWS($config); 

        //create a new session
        $icws->createSession(true);     

        while(1){

            $result = $icws->processMessage();
            echo json_encode($result);  

            ob_flush();
            flush();
            sleep(1);

        }

    } catch(Exception $e){
        echo $e->getMessage();
    }

    function apiAutoloader($className)
    {
        $className = ltrim($className, '\\');
        $fileName  = '';
        $namespace = '';

        if ($lastNsPos = strripos($className, '\\')) 
        {
            $namespace = substr($className, 0, $lastNsPos);
            $className = substr($className, $lastNsPos + 1);
            $fileName  = str_replace('\\', DIRECTORY_SEPARATOR, $namespace) . DIRECTORY_SEPARATOR;
        }

        $fileName .= str_replace('_', DIRECTORY_SEPARATOR, $className) . '.php';

        $toLoad = dirname(__FILE__).'/'.$fileName;

        if (is_file($toLoad) === true)
        {
            include $toLoad;
        }
    }
?>

当用户访问我的页面时,这是我运行的代码。
<script>

    $(function(){

        function isset(a, b){

            if(typeof a !== "undefined" && a){
                return a
            }

            return b;
        }


        var evtSource = new EventSource("poll.php");

        evtSource.onmessage = function(e) {

            $.each(e.data.calls, function(i, item){

                $.each(item, function(z, c){

                    var interactionId = isset(c.interactionId, 0);
                    var Eic_CallDirection = isset(c.Eic_CallDirection, '');
                    var Eic_State = isset(c.Eic_State, '');
                    var AccoRDI_mid = isset(c.AccoRDI_mid, '');
                    var Eic_RemoteAddress = isset(c.Eic_RemoteAddress, '');

                    if(Eic_State == '' || Eic_CallDirection == ''){
                        return;
                    }

                    //incoming call that is not answered
                    if( Eic_CallDirection == 'I' && Eic_State == 'A'){
                        console.log('Incomming Call From ' + Eic_RemoteAddress + ' MID: ' + AccoRDI_mid );
                        return;
                    }

                    //on hold
                    if( Eic_State == 'H'){
                        console.log('Phone number ' + Eic_RemoteAddress + ' is on hold' );
                        return;
                    }

                    //voicemail
                    if( Eic_State == 'M'){
                        console.log('Phone number ' + Eic_RemoteAddress + ' is on leaving a voicemail' );
                        return;
                    }

                    //connected call
                    if(Eic_State == 'C'){
                        console.log('Live Call With ' + Eic_RemoteAddress );
                        return;
                    }

                    //Dialling call
                    if(Eic_State == 'O'){
                        console.log('Dialling ' + Eic_RemoteAddress );
                        return;
                    }

                    //Dialling call
                    if(Eic_State == 'R'){
                        console.log('Outbound call is rining and waiting for answer ' );
                        return;
                    }

                    //Call Disconnected
                    if(Eic_State == 'I' || Eic_State == 'E' ){
                        console.log('Hungup with ' + Eic_RemoteAddress );
                        return;
                    }

                });
            });
        }
    });
</script>

我的代码无法正常工作。

我在控制台中没有看到任何输出,但是出现了这个错误:Firefox 无法连接到 /icws/poll.php 服务器

我该如何让它正常工作? 我实现的 PHP 脚本方式是否正确?


尝试使用ob_end_flush()代替。看起来存在缓冲问题。Apache / Nginx? - Axalix
仍然出现错误:“Firefox 无法连接到 /icws/poll.php 服务器。” - Jaylen
icws->processMessage(); 返回什么? - Zalaboza
@Zalaboza 它返回一个看起来像这样的数组 {"calls":[[{"interactionId":"2002927194","account_id":"9985","mid":"","Eic_CallDirection":"I","Eic_RemoteAddress":"5467893548","Eic_LocalAddress":"1062","Eic_State":"O"}]],"status":[{"statusId":"Available","userId":"user","loggedIn":true}]} - Jaylen
2个回答

1
浏览器请求事件源 PHP 文件的状态码是什么?请尝试使用 Firebug 确保其不是 404。此外,关于 PHP 代码。根据您在问题中提供的 Mozilla 源,服务器的适当响应应按名称分隔并由换行符分隔。
header("Content-Type: text/event-stream\n\n");     
while (1) {     
  echo "event: ping\n"; //event name
  echo 'data: '.json(); //event data
  Echo "\n\n"; //required  

  ob_flush(); flush(); sleep(1);    
 }

事件示例

event: userconnect
data: {"username": "bobby", "time": "02:33:48"} 

event: usermessage
data: {"username": "bobby", "time": "02:34:11", "text": "Hi everyone."} 

仍在工作中。现在出现错误:连接到https://accordi.rdimarketing.com/icws/poll.php的连接在页面加载时被中断。 - Jaylen
尝试直接打开页面,等待几分钟。 - Zalaboza
我在纠正问题后接受了你的答案。我会发布一个回答,详细说明我所做的一切,以帮助下一个人 :) - Jaylen

1
为了解决这个问题,我添加了一个监听器事件,代码如下:
        var evtSource = new EventSource("poll.php");

        evtSource.addEventListener("ping", function(e) {

          var obj = JSON.parse(e.data);
          processMessages(obj);

        }, false);

我写了如下的processMessages函数。
        function processMessages(obj) {

            $.each(obj.calls, function(i, item){

                $.each(item, function(z, c){

                    var interactionId = isset(c.interactionId, 0);
                    var Eic_CallDirection = isset(c.Eic_CallDirection, '');
                    var Eic_State = isset(c.Eic_State, '');
                    var mid = isset(c.mid, '');
                    var account_id = isset(c.account_id, '');
                    var Eic_RemoteAddress = isset(c.Eic_RemoteAddress, '');

                    if(Eic_State == '' || Eic_CallDirection == ''){
                        return;
                    }

                    //incoming call that is not answered
                    if( Eic_CallDirection == 'I' && Eic_State == 'A'){
                    var msg = '';
                        if(mid != ''){
                            msg = ' MID: ' + mid;
                        }

                        if(account_id != ''){
                            msg = ' Account ID: ' + account_id;
                        }
                        console.log('Incomming Call From ' + Eic_RemoteAddress + msg );
                        return;
                    }

                    //on hold
                    if( Eic_State == 'H'){
                        console.log('Phone number ' + Eic_RemoteAddress + ' is on hold' );
                        return;
                    }

                    //voicemail
                    if( Eic_State == 'M'){
                        console.log('Phone number ' + Eic_RemoteAddress + ' is on leaving a voicemail' );
                        return;
                    }

                    //connected call
                    if(Eic_State == 'C'){
                        console.log('Live Call With ' + Eic_RemoteAddress );
                        return;
                    }

                    //Dialling call
                    if(Eic_State == 'O' && Eic_CallDirection = 'O'){
                        console.log('Dialling ' + Eic_RemoteAddress );
                        return;
                    }

                    //Dialling call
                    if(Eic_State == 'R'){
                        console.log('Outbound call is rining and waiting for answer ' );
                        return;
                    }

                    //Call Disconnected
                    if(Eic_State == 'I' || Eic_State == 'E' ){
                        console.log('Hungup with ' + Eic_RemoteAddress );
                        return;
                    }

                });
            });
        }

而我的PHP代码看起来像这样:
    while(1){

        $result = array('test' => 'This is a test records');
        echo 'event: ping' . "\n";
        echo 'data: ' . json_encode($result) . "\n";    
        echo "\n"; //required  

        ob_flush(); flush(); sleep(1);   

    }

在PHP中有几个要注意的地方。每行代码后面都需要添加\n,并且在最后一行再加一个。同时,还需要查找关键字ping,它位于我的PHP代码和javascript代码的监听器事件中。如果你要更改它,必须在2个地方进行更改。
希望这能帮助到某些人 :)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接