SSE
是Server-Sent Events
的缩写。一般状况下,是咱们的浏览器向服务器发起请求后,服务器响应,而后关闭链接。为了可以保持通讯,以便在服务器有事件发生时主动通知浏览器,后来人们又发明了不少技术,包括websocket
等。可是websocket
对于代码改动较大,因此又出现了SSE
,它的特色是基本不用改写原有的逻辑,只是增长一些小的改动就能实现服务器与客户端之间的长链接,达到服务器主动通知客户端的目的。javascript
可是我在按照网上教程真正去在nginx
环境下实现SSE
时,颇费了一番周章,留在这里,以便有同窗遇到相似问题时参考。php
SSE
的主要原理是由客户端,也就是浏览器里的javascript
发起一个相似于ajax
的请求,但和ajax
不一样的是,这是一个一直保持的长链接,一旦请求创建以后,客户端开始安静地等待服务端向它发回数据,这个链接能够保持很长很长时间。java
因此客户端的代码很简单:nginx
source = new EventSource('http://api.server.com/path/file.php?param=value'); source.onmessage = function (event) { json = JSON.parse(event.data); ... 后面是你处理数据的部分 ... };
不用担忧断掉,即便断掉的话,客户端会在断掉以后的3秒以后自动再次从新向服务端发起链接请求,并且这个从新链接是浏览器自动帮助咱们实现的,咱们在编程时能够彻底不去考虑它。web
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 . "\n\n"; $old_md5 = $md5; } ob_flush(); flush(); //等待3秒钟,开始下一次查询 sleep(3); }
逐行分解一下:ajax
这三句话必不可少:编程
header('X-Accel-Buffering: no'); header('Content-Type: text/event-stream'); header('Cache-Control: no-cache');
其中的第一句话,是配置nginx
必需的。由于nginx
缺省会对全部来自php
的数据做缓存,它必定要等到全部数据所有写进缓存后才一股脑发给客户端,而咱们要创建的是一个很长的链接,这个链接过程当中随时可能要发送数据,不须要缓存,因此这里必须经过X-Accel-Buffering
告诉nginx
你对我这段代码不要给我作缓存,不然你会在客户端等很长很长时间却一个字符也收不到。json
注意后面那个100
次的for
循环,网上几乎全部的例子里在这里都会使用while(1)
的一个无限循环,但我我的的经验偏偏相反,在这里应该是一个for
循环,而不是while
循环。为何呢?由于咱们必须使得整个程序的执行时间可控,若是你用for
循环100
次,每次sleep
3秒钟的话,整个脚本的执行时长也就是在5分钟左右,而若是你使用while
无限循环的话,整个时间会几乎是无限长。有的同窗可能会说我在php.ini
里设置了max_excution_time
是60
秒钟啊,很好,我一开始也是这么认为的,可是:sleep(3)的时间不算在内!因此你能够想象一下你的脚本要执行多长时间才会结束并安静地从内存中退出去?api
最后,还须要配置nginx
,只须要一句话,在你的nginx.conf
的location
里:浏览器
fastcgi_read_timeout 600s;
这是因为nginx
在和咱们的php-fpm
进行通信的时候,这个地方的缺省值是60
,若是它等了60
秒,结果php-fpm
一个字符也没有送过来的话,nginx
会强行停止与咱们的程序的链接,但咱们的程序实际尚未执行结束,这时候js
客户端发现链接断了,就会自动重启一个新的链接,结果咱们服务器端的资源很快被耗尽了。在这里设为600
秒的意思是告诉nginx
,即便个人php
代码一个字符也不给你发送,你也必须老老实实呆够10
分钟才能够退出。而其实是,还记得咱们前面的for
循环吗?咱们会在100
次等待3
秒后,也就是5
分钟内退出咱们的php
脚本执行,不会凑够10
分钟的。因此这里很安全。