服务端推送方案
(1)Ajax 短轮询 Ajax 轮询主要通过页面端的 JS 定时异步刷新任务来实现数据的加载
如果我们使用ajax短轮询方式,需要后端提供方法,通过调用微信支付接口实现根据订单号查询支付状态的方法(参见查询订单API) 。 前端每间隔三秒查询一次,如果后端返回支付成功则执行页面跳转。
缺点:这种方式实时效果较差,而且对服务端的压力也较大。
(2)长轮询
长轮询主要也是通过 Ajax 机制,但区别于传统的 Ajax 应用,长轮询的服务器端会在没有数据时阻塞请求直到有新的数据产生或者请求超时才返回,之后客户端再重新建立连接获取数据。
如果使用长轮询,也同样需要后端提供方法,通过调用微信支付接口实现根据订单号查询支付状态的方法,只不过循环是写在后端的。
缺点:长轮询服务端会长时间地占用资源,如果消息频繁发送的话会给服务端带来较大的压力。
(3)WebSocket 双向通信 WebSocket 是 HTML5 中一种新的通信协议,能够实现浏览器与服务器之间全双工通信。如果浏览器和服务端都支持 WebSocket 协议的话,该方式实现的消息推送无疑是最高效、简洁的。并且最新版本的 IE、Firefox、Chrome 等浏览器都已经支持 WebSocket 协议,Apache Tomcat 7.0.27 以后的版本也开始支持 WebSocket。
RabbitMQ Web STOMP 插件
借助于 RabbitMQ 的 Web STOMP 插件,实现浏览器与服务端的全双工通信。从本质上说,RabbitMQ 的 Web STOMP 插件也是利用 WebSocket 对 STOMP 协议进行了一次桥接,从而实现浏览器与服务端的双向通信。
STOMP协议
STOMP即Simple (or Streaming) Text Orientated Messaging Protocol,简单(流)文本定向消息协议。前身是TTMP协议(一个简单的基于文本的协议),专为消息中间件设计。它提供了一个可互操作的连接格式,允许STOMP客户端与任意STOMP消息代理(Broker)进行交互。STOMP协议由于设计简单,易于开发客户端,因此在多种语言和多种平台上得到广泛地应用。
插件安装
我们进入rabbitmq容器,执行下面的命令开启stomp插件
rabbitmq-plugins enable rabbitmq_web_stomp rabbitmq_web_stomp_examples
消息推送测试
将stomp.min.js从https://www.bootcdn.cn/stomp.js/下载拷贝到web_portal工程
我们根据stomp的例子代码创建一个页面,内容如下:
<html> <head> <title>RabbitMQ Web STOMP Examples : Echo Server</title> <meta charset="UTF-8"> <script src="js/stomp.min.js"></script> </head> <script> var client = Stomp.client('ws://192.168.200.128:15674/ws'); var on_connect = function(x) { id = client.subscribe("/exchange/paynotify/xyz", function(d) { alert(d.body); }); }; var on_error = function() { console.log('error'); }; client.connect('guest', 'guest', on_connect, on_error, '/'); </script> </body> </html>
建立一个direct型的交换机
后端我是通过RabbitTemplate发送消息的,需要引进坐标
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
配置yml文件的
spring:
rabbitmq:
host: 192.168.200.128
通过routekey为xyz向该交换机发送消息即可。或者建立一个fanout型的交换机,这样不需要routeKey值了,订阅路径可以去掉xyz,设置为/exchange/paynotify/
rabbitTemplate.convertAndSend("paynotify","xyz", "你好");
更多说明
destination 在 RabbitMQ Web STOM 中进行了相关的定义,根据使用场景的不同,主要有以下 4 种:
-
1./exchange/<exchangeName>
对于 SUBCRIBE frame,destination 一般为/exchange/<exchangeName>/[/pattern] 的形式。先建立一个exchangeName的交换机,该 destination 会创建一个唯一的、自动删除的、绑定<exchangeName>交换机的 queue,并根据 pattern 将该 queue 绑定到所给的 exchange,实现对该队列的消息订阅。
对于 SEND frame,destination 一般为/exchange/<exchangeName>/[/routingKey] 的形式。这种情况下消息就会被发送到定义的 exchange 中,并且指定了 routingKey。
-
2./queue/<queueName> 对于 SUBCRIBE frame,destination 会定义<queueName>的共享 queue,先建立一个queueName的队列,并且实现对该队列的消息订阅。 对于 SEND frame,destination 只会在第一次发送消息的时候会定义<queueName>的共享 queue。该消息会被发送到默认的 exchange 中,routingKey 即为<queueName>。
-
3./amq/queue/<queueName> 这种情况下无论是 SUBCRIBE frame 还是 SEND frame 都不会产生 queue。但如果该 queue 不存在,SUBCRIBE frame 会报错。 对于 SUBCRIBE frame,destination 会实现对队列<queueName>的消息订阅。 对于 SEND frame,消息会通过默认的 exhcange 直接被发送到队列<queueName>中。
-
4./topic/<topicName> 对于 SUBCRIBE frame,destination 创建出自动删除的、非持久的 queue 并根据 routingkey 为<topicName>绑定到 amq.topic exchange 上,同时实现对该 queue 的订阅。 对于 SEND frame,消息会被发送到 amq.topic exchange 中,routingKey 为<topicName>。