即时交互的应用

在现代的 Web 应用中很多场景都需要运用到即时通讯,比如说最常见的支付回调,与三方登录。这些业务场景都基本需要遵循以下流程:

  • 客户端触发相关业务,并产生第三方应用的操作(比如支付)
  • 客户端等待服务端响应结果(用户完成第三方应用的操作)
  • 第三方应用通知服务端处理结果(支付完成)
  • 服务端通知客户端处理结果
  • 客户端依据结果做出反馈 (跳转到支付成功页面)

在过去,为了实现这种即时通讯,能让客户端正确响应处理结果,最为常用的技术就是轮询,因为 HTTP 协议的单向性,客户端只能一遍一遍的主动询问服务端的处理结果。这种方式有显见的缺陷,占用服务端资源不说,还不能实时获得服务端处理结果。

现在,我们可以使用 WebSocket 协议来处理实时交互,它是一种双向协议,允许服务端主动推送信息到客户端。本篇我们将借助 Laravel 强大的事件系统来构建实时的交互。你将需要用到以下知识:

  • Laravel Event
  • Redis
  • Socket.io
  • Node.js

Redis

在开始之前,我们需要开启一个 redis 服务,并在 Laravel 应用中进行配置启用,因为在整个流程中,我们需要借助 redis 的订阅和发布机制来实现即时通讯。

Redis 是一个开源高效的键值对存储系统。它通常作为一个数据结构服务器来存储键值对,它可以支持字符串,散列,列表,集合和有序结合。在 Laravel 中使用 Redis 你需用通过 Composer 来安装 predis/predis 包文件。

配置

Redis 在应用中的配置文件存储在 config/database.php,在这个文件中,你可以看到一个包含了 Redis 服务信息的 redis 数组:

'redis' => [
'cluster' => false, 'default' => [
'host' => '127.0.0.1',
'port' => 6379,
'database' => 0,
],
]

如果你修改了 redis 服务的端口,请保持配置文件中的端口一致。

Laravel Event

这里我们需要借助 Laravel 强大的事件广播能力:

广播事件

很多现代化的应用中,会使用 Web Sockets 来实现实时交互的用户接口。当一些数据在服务端变更时,一条消息会通过 WebSocket 连接来传递到客户端进行处理。
为了帮助你构建这种类型的应用。Laravel 使通过 WebSocket 连接进行广播事件变的非常简单。Laravel 允许你广播事件来共享事件的名称到你的服务端和客户端的 JavaScript 框架。

配置

所有的事件广播配置选项都被存储在 config/broadcasting.php 配置文件中。Laravel 附带了几种可用的驱动如 Pusher,Redis,和 Log,我们将使用 Redis 作为广播驱动,这里需要依赖 predis/predis 类库。

由于默认的广播驱动使用的是 pusher,所以我们需要在 .env 文件中设置 BROADCAST_DRIVER=redis

我们创建一个 WechatLoginedEvent 事件类用来在用户扫描微信登录后进行广播:

<?php

namespace App\Events;

use App\Events\Event;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast; class WechatLoginedEvent extends Event implements ShouldBroadcast
{
use SerializesModels; public $token;
protected $channel; /**
* Create a new event instance.
*
* @param string $token
* @param string $channel
* @return void
*/
public function __construct($token, $channel)
{
$this->token = $token;
$this->channel = $channel;
} /**
* Get the channels the event should be broadcast on.
*
* @return array
*/
public function broadcastOn()
{
return [$this->channel];
} /**
* Get the name the event should be broadcast on.
*
* @return string
*/
public function broadcastAs()
{
return 'wechat.login';
}
}

其中你需要注意 broadcastOn 方法应返回一个数组,它表示所需广播的频道,而 broadcastAs 返回的是一个字符串,它表示广播所触发的事件,Laravel 默认的是返回事件类的全类名,这里是 App\Events\WechatLoginedEvent.

最重要的是你需要手动的让该类实现 ShouldBroadcast 契约。Laravel 在生成事件时,已经自动添加了该命名空间,该契约只约束 broadcastOn 方法。

事件完成接下来就是触发事件了,简单的一行代码就可以:

event(new WechatLoginedEvent($token, $channel));

这个操作会自动的触发事件的执行并将信息广播出去。该广播操作底层借助了 redis 的订阅和发布机制。RedisBroadcaster 会将事件中的允许公开访问的数据通过给定的频道发布出去。如果你想对公开的数据拥有更多的控制,你可以在事件中添加 broadcastWith 方法,它应该返回一个数组:

/**
* Get the data to broadcast.
*
* @return array
*/
public function broadcastWith()
{
return ['user' => $this->user->id];
}

Node.js 和 Socket.io

对于发布出去的信息,我们需要一个服务来对接,让其能对 redis 的发布能够进行订阅,并且能把信息以 WebSocket 协议转发出去,这里我们可以借用 Node.js 和 socket.io 来非常方便的构建这个服务:

// server.js
var app = require('http').createServer(handler);
var io = require('socket.io')(app); var Redis = require('ioredis');
var redis = new Redis(); app.listen(6001, function () {
console.log('Server is running!') ;
}); function handler(req, res) {
res.writeHead(200);
res.end('');
} io.on('connection', function (socket) {
socket.on('message', function (message) {
console.log(message)
})
socket.on('disconnect', function () {
console.log('user disconnect')
})
}); redis.psubscribe('*', function (err, count) {
}); redis.on('pmessage', function (subscrbed, channel, message) {
message = JSON.parse(message);
io.emit(channel + ':' + message.event, message.data);
});

这里我们使用 Node.js 引入 socket.io 服务端并监听 6001 端口,借用 redis 的 psubscribe 指令使用通配符来快速的批量订阅,接着在消息触发时将消息通过 WebSocket 转发出去。

Socket.io 客户端

在 web 前端,我们需要引入 Socket.io 客户端开启与服务端 6001 端口的通讯,并订阅频道事件:

// client.js
let io = require('socket.io-client') var socket = io(':6001')
socket.on($channel + ':wechat.login', (data) => {
socket.close()
// save user token and redirect to dashboard
})

至此整个通讯闭环结束,开发流程看起来就是这样的:

  • 在 Laravel 中构建一个支持广播通知的事件
  • 设置需要进行广播的频道及事件名称
  • 将广播设置为使用 redis 驱动
  • 提供一个持续的服务用于订阅 redis 的发布,及将发布内容通过 WebSocket 协议推送到客户端
  • 客户端打开服务端 WebSocket 隧道,并对事件进行订阅,根据指定事件的推送进行响应。

有需要交流的小伙伴可以点击这里加本人QQ:luke

Laravel 即时应用的一种实现方式的更多相关文章

  1. Laravel框架定时任务2种实现方式示例

    本文实例讲述了Laravel框架定时任务2种实现方式.分享给大家供大家参考,具体如下: 第一种 1.生成一个commands文件 > php artisan make:command test ...

  2. 一种laravel特有的serviceProvider的加载方式

    这里的laravel版本5.5. 我是使用到dingo这个包的时候,觉得很奇怪,我们一般的包使用的时候都需要加载一个serviceProvider,提供服务,dingo/api这里也有ServiceP ...

  3. 通过三个DEMO学会SignalR的三种实现方式

    一.理解SignalR ASP .NET SignalR 是一个ASP .NET 下的类库,可以在ASP .NET 的Web项目中实现实时通信(即:客户端(Web页面)和服务器端可以互相实时的通知消息 ...

  4. SignalR代理对象异常:Uncaught TypeError: Cannot read property 'client' of undefined 推出的结论 SignalR 简单示例 通过三个DEMO学会SignalR的三种实现方式 SignalR推送框架两个项目永久连接通讯使用 SignalR 集线器简单实例2 用SignalR创建实时永久长连接异步网络应用程序

    SignalR代理对象异常:Uncaught TypeError: Cannot read property 'client' of undefined 推出的结论   异常汇总:http://www ...

  5. java框架之Hibernate(4)-几种检索方式

    准备 模型及映射文件 package com.zze.bean; import java.util.HashSet; import java.util.Set; public class Class ...

  6. 015-线程同步-synchronized几种加锁方式、Java对象头和Monitor、Mutex Lock、JDK1.6对synchronized锁的优化实现

    一.synchronized概述基本使用 为确保共享变量不会出现并发问题,通常会对修改共享变量的代码块用synchronized加锁,确保同一时刻只有一个线程在修改共享变量,从而避免并发问题. syn ...

  7. Java三种编译方式

    Java程序代码需要编译后才能在虚拟机中运行,编译涉及到非常多的知识层面:编译原理.语言规范.虚拟机规范.本地机器码优化等:了解编译过程有利于了解整个Java运行机制,不仅可以使得我们编写出更优秀的代 ...

  8. Ajax请求被缓存的几种处理方式

    Ajax请求被缓存的几种处理方式 我们都知道IE会针对ajax请求的地址缓存请求结果,直到缓存过期之前,针对相同地址发出的请求,只有第一次会请求会真正发送到服务端.在某种情况下,这种缓存机制确实能提高 ...

  9. 通过三个DEMO学会SignalR的三种实现方式 转载https://www.cnblogs.com/zuowj/p/5674615.html

    一.理解SignalR ASP .NET SignalR 是一个ASP .NET 下的类库,可以在ASP .NET 的Web项目中实现实时通信(即:客户端(Web页面)和服务器端可以互相实时的通知消息 ...

随机推荐

  1. Day 02 作业

    作业 一 什么是编程? 基于编程语言的语法格式将自己脑中里想让计算机做的事,写到文件中. 二 简述计算机五大组成 控制器,运算器,存储器,输入设备,输出设备 三 操作系统有什么用? 操作系统直接与硬件 ...

  2. IDEA 支持scala开发

    IDEA支持scala开发,需要安装scala插件,并且pom.xml也需要添加对应依赖. 1. 安装scala插件 下载地址:https://plugins.jetbrains.com/plugin ...

  3. static介绍、内部类、final、权限修饰符的作用范围

    static 关键字:(可用于修饰方法.变量)     static 特点:         static是静态修饰符,一般修饰成员变量.被static修饰的属于全局共享.被static修饰的成员属于 ...

  4. Docker常用命令-全

    原文内容来自于LZ(楼主)的印象笔记,如出现排版异常或图片丢失等问题,可查看当前链接: https://app.yinxiang.com/shard/s17/nl/19391737/9f6bf39e- ...

  5. 【CV现状-3.2】纹理与材质

    #磨染的初心--计算机视觉的现状 [这一系列文章是关于计算机视觉的反思,希望能引起一些人的共鸣.可以随意传播,随意喷.所涉及的内容过多,将按如下内容划分章节.已经完成的会逐渐加上链接.] 缘起 三维感 ...

  6. .net(C#数据库访问) Mysql,Sql server,Sqlite,Access四种数据库的连接方式

    便签记录Mysql,Sql server,Sqlite,Access四种数据库的简单连接方式 //using MySql.Data.MySqlClient; #region 执行简单SQL语句,使用M ...

  7. 多个 .NET 框架

    目录 应用程序编程接口 C# 和 .NET 版本控制 .NET Standard 目前存在多个 .NET 框架. Microsoft 的宗旨是在最大范围的操作系统和硬件平台上提供 .NET 实现. 下 ...

  8. CAD绘图效率低?教你4个CAD绘图技巧,绘图效率提升十倍

    CAD绘图一直是一个谜一样的存在,说它简单吧,很多人都无法完全精通,说它难吧,很多人也都自学成才了. 如何学好CAD绘图是个难题,但是老话说的好,只要思想不滑坡,办法总比困难多,掌握以下这些CAD绘图 ...

  9. 使用Navicat Keygen激活(破解)Navicat Premium 12

    1.到Navicat官网下载使用版本进行安装,具体操作不再详述.Navcat官网下载链接:http://www.navicat.com.cn/download/navicat-premium : 2. ...

  10. 看懂 游戏《Minecraft》的崩溃报告 服务端/客户端

    如何看懂Minecraft报错的关键信息. 让你如何看懂Minecraft报错 前言 一些俏皮话 寻找崩溃日志 打开崩溃日志 重要的事说三遍 下载文本编辑器 开始分析 深度分析 得出结论 修复报错 解 ...