HTML5服务器端推送事件 解决PHP微信墙推送问题

问题描述

以前的文章中《PHP微信墙制作,开源》已经用PHP搭建了一个微信墙获取信息的服务器,然后我就在想推送技术应该怎么解决,上一篇已经用了.NET 的signalr做了一个微信墙,PHP一直没什么好思路,本来想用websocket,但自己写socket要解析websocket协议,PHP有一个比较好的实现是workerman,github地址请戳这里,但是都不是很中意,昨天给自己做官网的时候,看了一下MDN,浏览发现了这个东西“使用服务器发送事件”,突然就有了思路,今天可以试一下这个。

HTML5 服务器推送事件 简介

服务器推送事件(Server-sent Events)是 HTML 5 规范中的一个组成部分,可以用来从服务端实时推送数据到浏览器端。相对于与之类似的 COMET 和 WebSocket 技术来说,服务器推送事件的使用更简单,对服务器端的改动也比较小。对于某些类型的应用来说(比如我们现在做的这个微信墙),服务器推送事件是最佳的选择。

在介绍 HTML 5 服务器推送事件之前,首先介绍一些上面提到的几种服务器端数据推送技术。第一种是 WebSocket。WebSocket 规范是 HTML 5 中的一个重要组成部分,已经被很多主流浏览器所支持,也有不少基于 WebSocket 开发的应用。正如名称所表示的一样,WebSocket 使用的是套接字连接,基于 TCP 协议。使用 WebSocket 之后,实际上在服务器端和浏览器之间建立一个套接字连接,可以进行双向的数据传输。WebSocket 的功能是很强大的,使用起来也灵活,可以适用于不同的场景。不过 WebSocket 技术也比较复杂,包括服务器端和浏览器端的实现都不同于一般的 Web 应用。

除了 WebSocket 之外,其他的实现方式是基于 HTTP 协议来达到实时推送的效果。第一种做法是简易轮询,即浏览器端定时向服务器端发出请求,来查询是否有数据更新.另一种是
COMET 技术,他改进了简易轮询的缺点,使用的是长轮询。不过 COMET 技术的实现在服务器端和浏览器端都需要第三方库的支持。

综合比较上面提到的 4 种不同的技术,简易轮询由于其本身的缺陷,并不推荐使用。COMET 技术并不是 HTML 5 标准的一部分,从兼容标准的角度出发,也不推荐使用。WebSocket 规范和服务器推送技术都是 HTML 5 标准的组成部分,在主流浏览器上都提供了原生的支持,是推荐使用的。不过 WebSocket 规范更加复杂一些,适用于需要进行复杂双向数据通讯的场景。对于简单的服务器数据推送的场景,使用服务器推送事件就足够了。

服务器推送事件的例子请看这里传送门,我们下面就直接使用这个技术制作微信墙了

服务器端

在这里我们接着使用上几篇文章中写好的PHP服务器,github地址在这里传送门。首先我们要在原来项目基础上新建一个文件夹,用来放置推送服务的脚本以及微信墙的html页面,如下图的push文件夹

接着我们将上篇文章中signalR制作微信墙开源写好的微信墙的页面拿过来,去掉其中signalr部分,加入服务器推送事件的代码,如下

  1. <script type="text/javascript">
  2. var serverData;
  3. window.onload = function () {
  4. init();
  5. }
  6. function init() {
  7. serverData = document.getElementById(‘serverData‘);
  8. var es = new EventSource(‘PushtoClient.php‘);
  9. es.onopen = openConnect;
  10. es.onmessage = getMessage;
  11. }
  12. function openConnect(e) {
  13. }
  14. function getMessage(e) {
  15. var data = $.parseJSON(e.data);
  16. $("#UL").append(‘<li>\
  17. <div class="single">\
  18. <div class="pic">\
  19. <img src="http://ouredaimage.qiniudn.com/touxiang.jpg">\
  20. </div>\
  21. <div class="message">\
  22. <div class="s-name">\
  23. <span>‘ + data.nick_name + ‘</span> :\
  24. </div>\
  25. <div class="s-word">‘ + data.content + ‘\
  26. </div>\
  27. </div>\
  28. </div>\
  29. </li>‘);
  30. Slide();
  31. $("#total-num").text(++total);
  32. }
  33. </script>

接着我们编写PHP脚本用来向页面推送需要上墙的信息,需要上墙的信息来自mongodb中的一个pushqueue的collection,这个队列表的信息由我们一会将创建的客户端提供,他从队列里面拿到一个数据推送出去后就会从队列里面删除这条数据,队列里面有数据就会一直发送,直到为空一直监听。代码如下

  1. while(true){
  2. header("Content-Type:text/event-stream");
  3. $connection = new MongoClient( "mongodb://ip" );
  4. $db = $connection->testwechat;
  5. $coll = $db->pushqueue;
  6. $cursor = $coll->findOne();
  7. if($cursor!=null){
  8. echo ‘data:‘ .json_encode($cursor);
  9. echo "\n\n";
  10. ob_flush();
  11. flush();
  12. print_r($cursor);
  13. $coll->remove(array("messageid",$curDate[‘messageid‘]));
  14. sleep(1);
  15. }
  16. }

客户端

上面我们创建好了服务端的时候提到一个问题,就是上墙信息队列里面的信息是需要我们使用客户端审核后存放到pushqueue这个collection里面的,这里我们创建一个Laravel项目,由于业务比较简单,我们直接在routes.php里面写业务代码如下,里面的mongodb帮助类是我们之前在服务器端代码里面是用过的,直接copy过来

  1. include __DIR__ . ‘/Mongo/MongoUtil.php‘;
  2. Route::get(‘/‘, function () {
  3. $mongoClient = new MongoUtil(‘testwechat‘);
  4. $list = $mongoClient->getTop100(‘message‘);
  5. return View::make(‘hello‘)->with(‘list‘, $list);
  6. });
  7. Route::get(‘add/{id}‘, function ($id) {
  8. $mongoClient = new MongoUtil(‘testwechat‘);
  9. $querydoc = array(‘_id‘ => new MongoId($id));
  10. $queryres = $mongoClient->finone(‘message‘, $querydoc);
  11. if($queryres!=null){
  12. $doc = array(
  13. ‘messageid‘ => $queryres[‘messageid‘],
  14. ‘fakeid‘ => $queryres[‘fakeid‘],
  15. ‘nick_name‘ => $queryres[‘nick_name‘],
  16. ‘content‘ => $queryres[‘content‘]
  17. );
  18. $mongoClient->insert(‘pushqueue‘, $doc);
  19. }
  20. return Redirect::to(‘/‘);
  21. });

接下来我们在view下创建一个hello.blade.php页面,里面的内容就是我们曾经写好的服务器从微信官网爬取的数据,简单用bootstrap搭建的,代码如下

  1. <!doctype html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1">
  6. <title>Laravel PHP Framework</title>
  7. <link rel="stylesheet" href="http://cdn.bootcss.com/bootstrap/3.3.1/css/bootstrap.min.css">
  8. <link rel="stylesheet" href="http://cdn.bootcss.com/bootstrap/3.3.1/css/bootstrap-theme.css">
  9. <script src="http://cdn.bootcss.com/bootstrap/3.3.1/js/bootstrap.min.js"></script>
  10. </head>
  11. <body>
  12. <div class="container">
  13. <nav class="navbar navbar-inverse" role="navigation">
  14. <div class="container-fluid">
  15. <!-- Brand and toggle get grouped for better mobile display -->
  16. <div class="navbar-header">
  17. <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
  18. <span class="sr-only">微上墙</span>
  19. <span class="icon-bar"></span>
  20. <span class="icon-bar"></span>
  21. <span class="icon-bar"></span>
  22. </button>
  23. <a class="navbar-brand" href="#">微上墙</a>
  24. </div>
  25. <!-- Collect the nav links, forms, and other content for toggling -->
  26. <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
  27. <ul class="nav navbar-nav">
  28. <li class="active"><a href="#">blog</a></li>
  29. <li><a href="#">github</a></li>
  30. </ul>
  31. </div><!-- /.navbar-collapse -->
  32. </div><!-- /.container-fluid -->
  33. </nav>
  34. <div class="bs-callout bs-callout-info">
  35. <h4>使用方法</h4>
  36. <p>定期刷新可以获得新消息</p>
  37. </div>
  38. <div class="row">
  39. <div class="col-md-12">
  40. <table class="table table-striped">
  41. <thead>
  42. <tr>
  43. <th>#</th>
  44. <th>名字</th>
  45. <th>内容</th>
  46. <th>上墙</th>
  47. </tr>
  48. </thead>
  49. <tbody>
  50. @foreach($list as $id => $value)
  51. <tr>
  52. <td>{{{ $value[‘nick_name‘]}}}</td>
  53. <td>{{{ $value[‘content‘]}}}</td>
  54. <td>{{{ $value[‘date_time‘]}}}</td>
  55. <td><a href="./add/{{$value[‘_id‘]}}">上墙</a> </td>
  56. </tr>
  57. @endforeach
  58. </tbody>
  59. </table>
  60. </div>
  61. </div>
  62. </div>
  63. </body>
  64. </html>

到这里我们的工作就都做好了,开启写好的爬取服务器,推送服务器,和客户端,点击上墙 good!效果如下

这里明显有一个PushtoClient.PHP 的连接,其实这里面可以不用写一个死循环也可以达到同样的效果

总结

这个系列就到这里,演示了PHP.NET的推送,模拟http等方面,并做了一系列的实例,尤其是最后一个服务器推送事件,以前我也是不知道的,最近在翻看w3c和MDN的一些文档,也是在无意中发现这个让我还比较满意的方法,以前项目中只是使用过websocket,长轮询。另外这个服务器推送事件 可以添加一些事件,客户端做监听,是自己需要的事件才会接受消息,可以用来做类似组推的功能,不过压力测等还没有做,不过作微信墙是足够了。总算满足了我那个“用最合适的技术解决合适的问题”的小心思。最后放上github地址:微信上墙PHP微信上墙.NET版本

时间: 2024-10-22 10:22:44

HTML5服务器端推送事件 解决PHP微信墙推送问题的相关文章

HTML5 服务器推送事件(Server-sent Events)实战开发

转自:http://www.ibm.com/developerworks/cn/web/1307_chengfu_serversentevent/ http://www.ibm.com/developerworks/cn/web/wa-lo-comet/     --comet长连接 服务器推送事件(Server-sent Events)是 HTML 5 规范中的一个组成部分,可以用来从服务端实时推送数据到浏览器端.相对于与之类似的 COMET 和 WebSocket 技术来说,服务器推送事件的

SSE技术详解:一种全新的HTML5服务器推送事件技术

前言 一般来说,Web端即时通讯技术因受限于浏览器的设计限制,一直以来实现起来并不容易,主流的Web端即时通讯方案大致有4种:传统Ajax短轮询.Comet技术.WebSocket技术.SSE(Server-sent Events).关于这4种技术方式的优缺点,请参考<Web端即时通讯技术盘点:短轮询.Comet.Websocket.SSE>.本文将专门讲解SSE技术. 服务器推送事件(Server-sent Events),简称SSE,是 HTML 5 规范中的一个组成部分,可以用来从服务端

HTML5服务器推送事件

目前客户端(浏览器)和服务端交互大致有以下几种方式: 1)form表单提交方式,适合访问量不大,对用户体验要求不高的web系统开发,或者页面整体刷新无伤大雅的场合,通信方向是客户端提交给服务端,是客户端主动发起: 2)Ajax方式,特点是用户体验好,无需页面整体刷新,对服务器压力也小,有利于客户端和服务端的解耦,也是目前广为使用的一种客户端服务端交互方式,它也是通过客户端发起请求,服务端接受处理,通信方向和form表单相同: 3)server-sent-event,它是服务端主动向客户端(浏览器

html5之服务器推送事件

用于服务器实时向客户端推送消息,这个是单向推送server to client 服务器端 header头 要想服务器端推送:在服务器端的报头要定义: header('Content-Type:text/event-stream'),服务器发送的响应内容应该使用这种`text/event-stream`的MIME;这样客户端才能理解你这是发送的不是普通的数据, eventsource对象才能识别 事件流 服务器端发送事件流(内容); 每执行一次php文件就产生一个事件流: 事件流是由多个消息组成:

springweb flux 服务器推送事件

以前做服务器推送一般用轮询,后端主动给客户端推送不是很好解决.有时候也可以采用websocket 现在看了springwebflux,用它自带的方法做服务器推送方便多了. 代码如下: import org.springframework.http.codec.ServerSentEvent; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotati

微信消息推送

1.微信消息推送测试 微信公众号测试入口         ------->接口网址不好找啊 点击使用手机扫码进入,右键保存测试公众号二维码,如下(后面测试要用) 如果有多个用户扫码关注,则都会在右边显示出来,这里我自己先扫进去 另外还要注意这里的appid和appsercet,我们后面测试也需要使用 1.1给指定用户发送自己给定的消息 测试: 这里的access_token其实就像自己的门牌号一样,每次给用户发送消息时候,你都要指明自己的门牌号,才能向指定用户发送消息 import json i

开发版速达微信订单推送

在开发如何进行微信推送订单信息之前,我们需要先了解下微信的一些规定和技术: 公众平台服务号.订阅号.企业号的相关说明 1.订阅号:主要偏于为用户传达资讯(类似报纸杂志),认证前后都是每天只可以群发一条消息: 2.服务号:主要偏于服务交互(类似银行,114,提供服务查询),认证前后都是每个月可群发4条消息: 3.企业号:主要用于公司内部通讯使用,需要先验证身份才可以关注成功企业号. 温馨提示: 1)如果想简单的发送消息,达到宣传效果,建议可选择订阅号: 2)如果想用公众号获得更多的功能,例如开通微

微信主动推送文本消息C#

1. 登陆,根据用户名和密码登陆到微信公众平台管理页面,获取token,模拟登陆请求地址:http://mp.weixin.qq.com/cgi-bin/login?lang=zh_CN,2. 登陆后,获取用户所有的信息,地址:https://mp.weixin.qq.com/cgi-bin/contactmanage?t=user/index&token=,根据前面的token.3. 发送消息,地址:https://mp.weixin.qq.com/cgi-bin/singlesend?t=a

解决Android微信HTML5 播放视频的问题(不显示控制条,可交互)

首先你需要知道以下内容: http://ad.weixin.qq.com/learn/2-3-3--%E9%80%9A%E7%94%A8%E5%BA%93 这是微信为广告商开放的API,我一直认为只有在微信投广告才能正常使用. 但是就在刚刚我尝试了一下,直接调用也是可以的(而且没有广告,至少目前是这样) 我们这里用到了微信提供的视频接口 :(点击上面的链接,速去查看) 这样直接解决了 android 微信下 播放视频会调用特殊播放器播放的情况.(为什么?请看文末) 但是这样虽然解决了播放“层”的