资讯专栏INFORMATION COLUMN

在nginx下利用php配置SSE的正确方法

hzx / 3949人阅读

摘要:简介是的缩写。通常情况下,是我们的浏览器向服务器发起请求后,服务器响应,然后关闭连接。为了能够保持通信,以便在服务器有事件发生时主动通知浏览器,后来人们又发明了很多技术,包括等。

SSE简介

SSEServer-Sent Events的缩写。通常情况下,是我们的浏览器向服务器发起请求后,服务器响应,然后关闭连接。为了能够保持通信,以便在服务器有事件发生时主动通知浏览器,后来人们又发明了很多技术,包括websocket等。但是websocket对于代码改动较大,所以又出现了SSE,它的特点是基本不用改写原有的逻辑,只是增加一些小的改动就能实现服务器与客户端之间的长连接,达到服务器主动通知客户端的目的。

但是我在按照网上教程真正去在nginx环境下实现SSE时,颇费了一番周章,留在这里,以便有同学遇到类似问题时参考。

客户端

SSE的主要原理是由客户端,也就是浏览器里的javascript发起一个类似于ajax的请求,但和ajax不同的是,这是一个一直保持的长连接,一旦请求建立之后,客户端开始安静地等待服务端向它发回数据,这个连接可以保持很长很长时间。

所以客户端的代码很简单:

source = new EventSource("http://api.server.com/path/file.php?param=value");
source.onmessage = function (event) {
    json = JSON.parse(event.data);
    ... 后面是你处理数据的部分 ...
};

不用担心断掉,即使断掉的话,客户端会在断掉之后的3秒之后自动再次重新向服务端发起连接请求,而且这个重新连接是浏览器自动帮助我们实现的,我们在编程时可以完全不去考虑它。

服务器端 php部分
header("Access-Control-Allow-Origin: http://www.server.com");
//发送SSE应答
header("X-Accel-Buffering: no");
header("Content-Type: text/event-stream");
header("Cache-Control: no-cache");

$old_md5 = "";
//执行100次,每次睡眠3秒钟,总共300秒,也就是5分钟
for ($i=0; $i<100; $i++) {
    //保持一个长连接,每隔3秒钟回答客户端一次
    $o_data = 你的数据;
    $str_return = json_encode($o_data);
    $md5 = md5($str_return);
    if ($md5 != $old_md5) {
        //如果内容发生了变化,则推送,否则不必推送,以节省网络流量
        echo "data: " . $str_return . "

";
        $old_md5 = $md5;
    }
    ob_flush();
    flush();
    //等待3秒钟,开始下一次查询
    sleep(3);
}

逐行分解一下:

这三句话必不可少:

header("X-Accel-Buffering: no");
header("Content-Type: text/event-stream");
header("Cache-Control: no-cache");

其中的第一句话,是配置nginx必需的。因为nginx缺省会对所有来自php的数据作缓存,它一定要等到所有数据全部写进缓存后才一股脑发给客户端,而我们要建立的是一个很长的连接,这个连接过程中随时可能要发送数据,不需要缓存,所以这里必须通过X-Accel-Buffering告诉nginx你对我这段代码不要给我做缓存,否则你会在客户端等很长很长时间却一个字符也收不到。

注意后面那个100次的for循环,网上几乎所有的例子里在这里都会使用while(1)的一个无限循环,但我个人的经验恰恰相反,在这里应该是一个for循环,而不是while循环。为什么呢?因为我们必须使得整个程序的执行时间可控,如果你用for循环100次,每次sleep 3秒钟的话,整个脚本的执行时长也就是在5分钟左右,而如果你使用while无限循环的话,整个时间会几乎是无限长。有的同学可能会说我在php.ini里设置了max_excution_time60秒钟啊,很好,我一开始也是这么认为的,但是:sleep(3)的时间不算在内!所以你可以想象一下你的脚本要执行多长时间才会结束并安静地从内存中退出去?

nginx设置

最后,还需要配置nginx,只需要一句话,在你的nginx.conflocation里:

fastcgi_read_timeout 600s;

这是由于nginx在和我们的php-fpm进行通讯的时候,这个地方的缺省值是60,如果它等了60秒,结果php-fpm一个字符也没有送过来的话,nginx会强行中止与我们的程序的连接,但我们的程序实际还没有执行结束,这时候js客户端发现连接断了,就会自动重启一个新的连接,结果我们服务器端的资源很快被耗尽了。在这里设为600秒的意思是告诉nginx,即使我的php代码一个字符也不给你发送,你也必须老老实实呆够10分钟才可以退出。而实际上是,还记得我们前面的for循环吗?我们会在100次等待3秒后,也就是5分钟内退出我们的php脚本执行,不会凑够10分钟的。所以这里很安全。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/21761.html

相关文章

  • nginx利用php配置SSE正确方法

    摘要:简介是的缩写。通常情况下,是我们的浏览器向服务器发起请求后,服务器响应,然后关闭连接。为了能够保持通信,以便在服务器有事件发生时主动通知浏览器,后来人们又发明了很多技术,包括等。 SSE简介 SSE是Server-Sent Events的缩写。通常情况下,是我们的浏览器向服务器发起请求后,服务器响应,然后关闭连接。为了能够保持通信,以便在服务器有事件发生时主动通知浏览器,后来人们又发明...

    he_xd 评论0 收藏0
  • 腾讯云使用笔记一: 腾讯云重装记录

    摘要:或少了因为启动时不是账号,就会这样前面别忘了加文件直接下载,不解析因为没有配置的解决办法引起通常是三种情况一是缺少索引文件,二是权限问题,三是状态。 ========腾讯云重装记录================ 安装时间:2018-09-09 12:15开始,结束时间: 一:重装操作系统 进入腾讯云后台,微信扫码登录 选择主机/更多/重装系统/服务市场/Docker容器/腾讯云容器...

    ashe 评论0 收藏0
  • 腾讯云使用笔记一: 腾讯云重装记录

    摘要:或少了因为启动时不是账号,就会这样前面别忘了加文件直接下载,不解析因为没有配置的解决办法引起通常是三种情况一是缺少索引文件,二是权限问题,三是状态。 ========腾讯云重装记录================ 安装时间:2018-09-09 12:15开始,结束时间: 一:重装操作系统 进入腾讯云后台,微信扫码登录 选择主机/更多/重装系统/服务市场/Docker容器/腾讯云容器...

    xiaotianyi 评论0 收藏0

发表评论

0条评论

hzx

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<