Laravel 即時應用的一種實現方式

即時交互的應用

在現代的 Web 應用中不少場景都須要運用到即時通信,好比說最多見的支付回調,與三方登陸。這些業務場景都基本須要遵循如下流程:javascript

  • 客戶端觸發相關業務,併產生第三方應用的操做(好比支付)
  • 客戶端等待服務端響應結果(用戶完成第三方應用的操做)
  • 第三方應用通知服務端處理結果(支付完成)
  • 服務端通知客戶端處理結果
  • 客戶端依據結果作出反饋 (跳轉到支付成功頁面)

在過去,爲了實現這種即時通信,能讓客戶端正確響應處理結果,最爲經常使用的技術就是輪詢,由於 HTTP 協議的單向性,客戶端只能一遍一遍的主動詢問服務端的處理結果。這種方式有顯見的缺陷,佔用服務端資源不說,還不能實時得到服務端處理結果。php

如今,咱們可使用 WebSocket 協議來處理實時交互,它是一種雙向協議,容許服務端主動推送信息到客戶端。本篇咱們將藉助 Laravel 強大的事件系統來構建實時的交互。你將須要用到如下知識:前端

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

Redis

在開始以前,咱們須要開啓一個 redis 服務,並在 Laravel 應用中進行配置啓用,由於在整個流程中,咱們須要藉助 redis 的訂閱和發佈機制來實現即時通信。java

Redis 是一個開源高效的鍵值對存儲系統。它一般做爲一個數據結構服務器來存儲鍵值對,它能夠支持字符串,散列,列表,集合和有序結合。在 Laravel 中使用 Redis 你需用經過 Composer 來安裝 predis/predis 包文件。web

配置

Redis 在應用中的配置文件存儲在 config/database.php,在這個文件中,你能夠看到一個包含了 Redis 服務信息的 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 隧道,並對事件進行訂閱,根據指定事件的推送進行響應。
相關文章
相關標籤/搜索