RabbitMQ通过websocket与前端通信

应用场景

做过微信h5支付的应该都知道,用户支付完会出现等待页面,在这个页面 前端会通过不断请求服务端接口的方式 获取支付结果。这种轮询的方式会对服务器造成一定的压力,下面我们就用 RabbitMQ 实现一下

先看下结果,如下图。客户端订阅order-99的队列,服务向order-99推数据,客户端可以实时收到

20210925173525.jpg

目录结构

测试

docker-compose up -d

# 验证 web stomp 插件是否激活
http://localhost:15670/

# rabbitmq管理后台
http://localhost:15672

代码

docker-compose.yml

version: '3'

networks:
  web-network:

services:
  docker-rabbitmq:
    environment:
#      RABBITMQ_DEFAULT_VHOST: "/"
      RABBITMQ_DEFAULT_USER: "guest"
      RABBITMQ_DEFAULT_PASS: "guest"
    image: "rabbitmq:3.9.5-management"
    restart: always
    tty: true
    volumes:
      - ./rabbitmq/enabled_plugins:/etc/rabbitmq/enabled_plugins
      - ../apps/rabbitmq/data:/var/lib/rabbitmq
      - ../apps/rabbitmq/log:/var/log/rabbitmq
    ports:
      - 15670:15670
      - 15674:15674
      - 15672:15672
      - 5672:5672
    networks:
      - web-network

./rabbitmq/enabled_plugins

[rabbitmq_management,rabbitmq_prometheus,rabbitmq_web_stomp,rabbitmq_web_stomp_examples].

composer.json

{
  "require": {
    "php-amqplib/php-amqplib": "^3.0"
  }
}

rabbitmq.php

<?php
require_once __DIR__ . '/../../vendor/autoload.php';

use PhpAmqpLib\Channel\AMQPChannel;
use PhpAmqpLib\Connection\AMQPStreamConnection;
use PhpAmqpLib\Message\AMQPMessage;
class rabbitmq {
    private $connection;
    private $channel;
    public $conf=[
        'host'=>'docker-rabbitmq',
        'port'=>5672,
        'user'=>'guest',
        'password'=>'guest'
    ];

    public static function factory(){
        return new self();
    }

    public function message($message, $properties=[]) {
        $properties= array_merge(['content_type' => 'text/plain', 'delivery_mode' => AMQPMessage::DELIVERY_MODE_PERSISTENT], $properties);
        return new AMQPMessage($message, $properties);
    }

    public function connection() {
        $this->connection = new AMQPStreamConnection($this->conf['host'], $this->conf['port'], $this->conf['user'], $this->conf['password']);
        return $this->connection;
    }
    /**
     * @param null $channel_id
     * @return AMQPChannel
     */
    public function channel($channel_id = null) {
        $this->channel=$this->connection->channel($channel_id);
        return $this->channel;
    }

//    public function __destruct(){
//        $this->channel->close();
//        $this->connection->close();
//    }

}

producer.php

<?php
require './rabbitmq.php';
$amqp=rabbitmq::factory();
$connection=$amqp->connection();
$channel=$amqp->channel();

$channel->queue_declare('order-99', false, true, false, false);
$channel->basic_publish($amqp->message(json_encode(['id'=>99, 'title'=>'order-99', 'status'=>1], JSON_UNESCAPED_UNICODE)), '', 'order-99');

$channel->close();
$connection->close();
echo 'ok';

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>My WebSocket</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/stomp.js/2.3.3/stomp.min.js"></script>
</head>
<body>
<script>
    /*
      首先访问:http://localhost:15670/,验证 web stomp 插件是否激活
       */
    if (typeof WebSocket == 'undefined') {
        console.log('不支持websocket')
    }

    // 初始化 ws 对象
    var ws = new WebSocket('ws://localhost:15674/ws');
    var client = Stomp.over(ws);

    var on_connect = function() {
        client.subscribe("order-99", function(message) {
            let result = message.body;
            console.log("收到数据:"+result)
            let r=JSON.parse(result);
            if (r.status===1){
                console.log('已支付');
                message.ack();//确认消息
            }
            // message.nack();//消息驳回,要求ack模式为{ack: 'client-individual'}
            //https://www.cnblogs.com/piaolingzxh/p/5463918.html

        }, {ack: 'client'});
        console.log('connected');
    };
    var on_error =  function() {
        console.log('error');
    };
    // 连接RabbitMQ
    //参数依次为:用户名,密码,连接后,出错,虚拟主机名
    client.connect('guest', 'guest', on_connect, on_error, '/');
    // console.log(">>>连接上http://localhost:15674");
</script>
</body>
</html>

关于STOMP

https://www.cnblogs.com/piaolingzxh/p/5463918.html

https://my.oschina.net/feinik/blog/853875

https://www.cnblogs.com/goloving/p/10746378.html

感谢阅读这篇文章,如果你喜欢,或者遇到了问题,可以关注我的公众号