利用laravel-echo主动向服务端发送消息,实现在线状态管理
之前在网上翻了半天,也没有找到关于如何 通过laravel-echo
主动发送消息 和 在laravel-websockets
中自定义控制器 的文章或教程。无奈之下只能翻laravel-echo
和laravel-websockets
的源码了,小有收获。在此为有需要的朋友指个方向,少踩一个坑。
开始吧
书接上回《利用websocket实现手机扫码登陆后,同步登陆信息到web端页面》,我们已经实现服务器主动向网页发送消息的功能了。但是,在使用laravel-echo
时,网页想主动向服务器发送消息该怎么做呢?首先,最简单的就是Ajax
异步请求了,写起来很容易。还有一种方式就是通过websocket
了,既然已经建立了 socket 连接,我们何不利用他来进行双向通信呢!这就是本文的重点内容:如何使用laravel-echo
通过websocket
进行反向通信(这里的「反向」指从网页向服务器发送消息)。
主要流程
简述
在上一篇 文章 的案例中,websocket 默认监听的地址是http://<your.host>:<wsPort>/app/<key>
。url 中的/app/
部分是pusher
中规定的,目前还无法修改。<key> 指实例化Echo
时的参数「key」,同时也是.env
文件中的PUSHER_APP_KEY
环境变量。后台控制器是laravel-websockets
已经定义好的 websocket 控制器:BeyondCode\LaravelWebSockets\WebSockets\WebSocketHandler
。现在我们要实现自己的控制器,来做在线状态管理,所以就需要改变 websocket 默认监听的地址和后台控制器。
修改前端监听地址
打开app/resources/views/hellow.blade.php
视图文件,在初始化Echo
中的参数部分加入wsPath
变量。此时 websocket 监听的地址就会变为http://<your.host>:<wsPort><wsPath>/app/<key>
。
window.Echo = new Echo({
broadcaster: 'pusher',
key: 'joker',
// 在 socket 链接中设置 url 路径
wsPath: '/liam/hao',
wsHost: location.hostname,
wsPort: 2020,
forceTLS: false,
});
注意:
wsPath
变量一定要用 “/” 开头,否则会报错的
后端添加新的路由
因为前端改变了监听路由,对应的后端,也需要新增一个对应的路由。我们打开routes/web.php
文件,加入以下新路由:
Route::get('/login', function () {
return view('login');
});
// 这个是 laravel-websockets 提供的门面方法,用来注册自定义的 websocekt 路由
// WebSocketsRouter 绑定的实际对象是 BeyondCode\LaravelWebSockets\Server\Router 有兴趣的可以瞅瞅
\BeyondCode\LaravelWebSockets\Facades\WebSocketsRouter::webSocket('/liam/hao/app/{appKey}', \App\Http\Controllers\MyWebsocketHandler::class);
创建自定义控制器
上面的路由中绑定了一个App\Http\Controllers\MyWebsocketHandler
类,现在我们就来实现这个类:
> php artisan make:controller MyWebsocketHandler
Controller created successfully.
执行上面的命令后,我们会在app/Http/Controllers
文件夹中找到MyWebsocketHandler.php
文件,我们来进行一些修改:
<?php
namespace App\Http\Controllers;
use BeyondCode\LaravelWebSockets\WebSockets\Messages\PusherMessageFactory;
use BeyondCode\LaravelWebSockets\WebSockets\WebSocketHandler;
use Ratchet\ConnectionInterface;
use Ratchet\RFC6455\Messaging\MessageInterface;
// 注意这里要继承自 WebSocketHandler
class MyWebsocketHandler extends WebSocketHandler
{
public function onMessage(ConnectionInterface $connection, MessageInterface $message)
{
var_dump(json_decode($message->getPayload()));
$message = PusherMessageFactory::createForMessage($message, $connection, $this->channelManager);
$message->respond();
}
public function onClose(ConnectionInterface $connection)
{
$this->channelManager->removeFromAllChannels($connection);
var_dump('close');
}
}
好了,我们现在来小测一下,看看新的路由有没有生效。重启laravel-websockets
的 http 服务。打开浏览器的开发者工具,然后刷新页面。如果像下图一样,在命令行终端里看到了我们var_dump()
的数据,那就说明新的路由和控制器已经连通了:
注意:MyWebsocketHandler 并不是一般的 Controller,他需要继承自
BeyondCode\LaravelWebSockets\WebSockets\WebSocketHandler
。如果你需要控制更多逻辑,可直接实现Ratchet\WebSocket\MessageComponentInterface
接口,并自己实现onOpen()
、onClose()
、onMessage()
等方法。
前端发送消息(重点)
重点来了哈,虽说是重点,但代码很简单:
Echo.channel('abcdefg.'+uuid)
.listen('LoginedEvent', (e) => {
console.log(e);
var session_id = e.session_id;
location.href = location.origin+'/hello?session_id='+session_id;
});
// 我们在这里放置一个定时器,每三秒钟向服务器发送一条数据
setInterval(function(){
// 这里新增一个向服务端发送消息的方法
// 第一个参数是事件名,这个可以随意写,不需要与 Laravel 中做对应
// 第二个参数是具体数据,这个就更随意了
Echo.connector.pusher.send_event('hi_girl', {
my_name: 'LiamHao',
my_height: 180,
});
}, 3000);
是不是很简单,我们再来小测一下,看看服务端接收到的数据是什么样子的:
后端已经接收到数据了。做到这里,想必有些基础的朋友应该已经可以做自己想做的事情了。
设置在线状态
这里我们就不做太复杂了数据库操作了,还是老样子,以最简单的方式,用 缓存 做记录吧。我们在App\Http\Controllers\MyWebsocketHandler
的onMessage()
和onClose()
方法中分别加入记录状态的代码:
public function onMessage(ConnectionInterface $connection, MessageInterface $message)
{
var_dump(json_decode($message->getPayload()));
// 每当收到消息时,设置当前连接状态为“在线”,60 秒后过期
\Cache::put($connection->socketId, '在线', 60);
$message = PusherMessageFactory::createForMessage($message, $connection, $this->channelManager);
$message->respond();
}
public function onClose(ConnectionInterface $connection)
{
$this->channelManager->removeFromAllChannels($connection);
var_dump('close');
// 浏览器主动断开连接时,设置当前连接状态为“离线”,不设置过期时间
\Cache::put($connection->socketId, '离线');
}
然后修改下app/resources/views/login.blade.php
视图文件,在页面中显示连接的状态:
<body>
<input type="text" name="username">
<input type="text" name="password">
<button>登陆</button>
<!-- 我们在这里简单的展示一下连接的状态 -->
<h1>Websocket 连接列表</h1>
<!-- 用 blade 模板语法渲染数据,简单的打印下数据 -->
<pre>{{ var_export(\Cache::get('socekt-status')) }}</pre>
</body>
大功告成,我们来看下效果。先打开http://<your.host>/login
页面,此时未显示任何内容。这是正常的,因为Cache
中还没有记录任何信息。接下来再打开http://<your.host>/hello
页面,看下浏览器开发者工具中 websocket 已连接成功。下面见证奇迹的时刻到了,我们再将http://<your.host>/login
页面刷新一次,此时会看到Cache
中记录的在线状态信息:
我们再来试下断开 websocekt 连接时,是否会显示离线。将http://<your.host>/login
页面直接关闭,也就是点标签页上的「叉子」。再刷新下http://<your.host>/hello
页面:
本文尽量简化过程,减少无关操作,也将实现步骤尽可能详细的展现出来看,希望能对大家有所帮助。
利用laravel-echo主动向服务端发送消息,实现在线状态管理的更多相关文章
- Query通过Ajax向PHP服务端发送请求并返回JSON数据
Query通过Ajax向PHP服务端发送请求并返回JSON数据 服务端PHP读取MYSQL数据,并转换成JSON数据,传递给前端Javascript,并操作JSON数据.本文将通过实例演示了jQuer ...
- Java实现UDP之Echo客户端和服务端
Java实现UDP之Echo客户端和服务端 代码内容 采用UDP协议编写服务器端代码(端口任意) 编写客户机的代码访问该端口 客户机按行输入 服务器将收到的字符流和接收到的时间输出在服务器consol ...
- Java实现TCP之Echo客户端和服务端
Java实现TCP之Echo客户端和服务端 代码内容 采用TCP协议编写服务器端代码(端口任意) 编写客户机的代码访问该端口 客户机按行输入 服务器将收到的字符流和接收到的时间输出在服务器consol ...
- jQuery通过Ajax向PHP服务端发送请求并返回JSON数据
SON(JavaScript Object Notation) 是一种轻量级的数据交换格式.易于人阅读和编写,同时也易于机器解析和生成.JSON在前后台交互的过程中发挥着相当出色的作用.请接着往下看教 ...
- 利用WebSocket和EventSource实现服务端推送
可能有很多的同学有用 setInterval 控制 ajax 不断向服务端请求最新数据的经历(轮询)看下面的代码: setInterval(function() { $.get('/get/data- ...
- Diango之通过form表单向服务端发送数据
通过form表单向服务端发送数据 表单元素 表单:form></form>表单用于向服务器传输数据.另外一种向服务端传输数据的方式为ajax. form属性: action:提交表单 ...
- socket小程序写一个客户端,实现给服务端发送hello World字符串,将客户端发送的数据变成大写后返回
写一个客户端,实现给服务端发送hello World字符串,将客户端发送的数据变成大写后返回 本机id是192.168.xx.xy 服务端 import socket soc = socket.soc ...
- 记一次压测问题定位:connection reset by peer,TCP三次握手后服务端发送RST_网络_c359719435的专栏-CSDN博客 https://blog.csdn.net/c359719435/article/details/80300433
记一次压测问题定位:connection reset by peer,TCP三次握手后服务端发送RST_网络_c359719435的专栏-CSDN博客 https://blog.csdn.net/c3 ...
- AgileEAS.NET SOA 中间件平台.Net Socket通信框架-简单例子-实现简单的服务端客户端消息应答
一.AgileEAS.NET SOA中间件Socket/Tcp框架介绍 在文章AgileEAS.NET SOA 中间件平台Socket/Tcp通信框架介绍一文之中我们对AgileEAS.NET SOA ...
随机推荐
- Python 交互式解释器的二三事
学 Python 不知道何时起成了一种风尚.这里,我也随便聊聊跟Python 的交互式解释器的几个有意思的小问题. 如何进入 Python 交互解释器? 当你安装好 Python 后,如何进入 Pyt ...
- EntityFramwork常见问题
1.常用的语句有哪些 添加migration dotnet ef migrations add [MIgrationName] 删除刚添加的migration dotnet ef ...
- bellman-ford 单源最短路问题 图解
核心思想:松弛操作 对于边(u,v),用dist(u)和(u,v)的和尝试更新dist(v): dist(v) = min(dist(v) , dist(u)+l(u,v) 注:dist(i)为源 ...
- 『现学现忘』Git基础 — 18、Git对象的总结
目录 1.Git操作最基本的流程 2.工作目录中文件的状态 3.Git效率说明 提示:前面三篇文章已经分别的对blob对象.tree对象.commit对象进行了详细的说明,这篇文章我们总结一下,Git ...
- rabbitmq 安装延时队列插件rabbitmq-delayed-message-exchange
1.下载rabbitmq-delayed-message-exchange(注意版本对应) 链接:https://github.com/rabbitmq/rabbitmq-delayed-messag ...
- Ubuntu 系统安装,VMware
系统版本 ubuntu-18.04.5-server-amd64.iso 1.自定义安装 2.默认下一步 3. 稍后安装操作系统 4.选择ubuntu 64位 5.选额安装的目录 6.设置虚拟机c ...
- vuepress搭建UI组件库文档踩坑篇
为了实现组件效果预览及代码展示可折叠功能,使用了插件vuepress-plugin-demo-container 相关配置可参考官网说明文档 第一步 安装插件 npm i - D vuepress-p ...
- 小程序扫码、上传图片、css时间轴
de <!-- 导航 --> <view class="navSec flexBox"> <text class="navItem {{ s ...
- unity---GL实现案例
GL C#实现 不管是画任何东西都需要Begin()和End()函数: 画线 using System.Collections; using System.Collections.Generic; u ...
- 126_Power BI中使用DAX计算股票RSI及股票均线相关
博客:www.jiaopengzi.com 焦棚子的文章目录 请点击下载附件 一.背景 前些日子,有朋友在交流股票RSI用DAX处理的问题,由于RSI股票软件的算法几乎都是需要用到股票从上市第一天开始 ...