文档结构  
翻译进度:已翻译     翻译赏金:0 元 (?)    ¥ 我要打赏

想象一个可以提醒用户某个事件的App,你希望提醒是实时的...

Web socketSocket.IO让这种想法成为可能。但是Laravel本身并没有对http socket提供直接的支持,因此我们必须实现一个小型的NodeJSSocket.IO服务器,并且实现从Laravel后端推送消息。

要实现两个不同的Laravel5NodeJS后端服务器之间进行交互,我们将会使用Redis。Redis是一个带有发布/订阅特性的键值存储,每一个发布到指定队列的消息将会分发给每个订阅者,这里我们的订阅者是NodeJS服务器。

第 1 段(可获 2 积分)

安装Redis

Redis的安装是非常简单的,在从官方网站下载当前最新的稳定版之后,解压并且执行下列脚本:

make

当脚本执行结束的时候,你可以启动服务器。本教程中,我们将会使用它的默认配置,因此不需要对它做任何修改。

src/redis-server

这里有一个实用的工具可以用来验证连接和推送消息到队列中。
redis-cli monitor

NodeJS服务器

NodeExpressserver 是一个实现了Socket.io服务器的便捷应用。最大的不同是它包含了Redis订阅部分。服务器将会是Redis队列消息的订阅者。当一个新的消息被发布到队列的时候,它将会产生同样的消息给所有连接的客户端。

第 2 段(可获 2 积分)

Laravel的根文件夹中创建一个子文件夹存放NodeJS服务器。在子文件夹中使用npm安装下面的包

npm install express redis socket.io --save

服务器的代码将会在server.js文件中

var app = require('express')();
var server = require('http').Server(app);
var io = require('socket.io')(server);
var redis = require('redis');
 
server.listen(8890);
io.on('connection', function (socket) {
 
  console.log("new client connected");
  var redisClient = redis.createClient();
  redisClient.subscribe('message');
 
  redisClient.on("message", function(channel, message) {
    console.log("mew message in queue "+ message + "channel");
    socket.emit(channel, message);
  });
 
  socket.on('disconnect', function() {
    redisClient.quit();
  });
 
});

上述代码是自注释的,应该很容易理解。

我们在8090端口上开始一个http服务器,并且建立与Socket.IO服务器的关联,然后创建一个Redis客户端,之后当新的socket客户端连接的时候,我们会从Redis的消息队列中订阅消息。

当推送消息到消息队列中时,每一个客户端都会发生一个socket.emit的事件。

从命令行中启动服务器,需要先切换到NodeJS文件夹中,然后执行下面的命令

node server.js

第 3 段(可获 2 积分)

Laravel中使用Redis

在Laravel 5中已经配置了Redis,但是使用它是你需要先做一些在官方文档中没有提及的修改。首先你需要安装predis。你可以通过composer下载它,在composer.json中添加下面这条记录后执行update

"require": {
		"laravel/framework": "5.0.*",
	        "predis/predis": "~1.1@dev"
	},
composer update

为了避免与PHP环境中的Redis发生冲突,我们需要修改Laravel中Redis模块的别名。在配置文件app.php中修改以下配置

'Redis'    => 'Illuminate\Support\Facades\Redis',

修改为以下内容

'LRedis'    => 'Illuminate\Support\Facades\Redis',
这就是所有需要修改的内容,之后我们就正常在Laravel中使用Redis了。
第 4 段(可获 2 积分)

Laravel应用

对于Laravel这边来说,我们仅仅需要实现一个非常基本的应用,只有两个页面,一个用于发送消息,另一个用于不重新加载页面的情况下实时的接收消息。所有的实现逻辑都在socketController控制器中。

php artisan make:controller socketController

在这个控制器中,我们需要实现三个方法。前两个用于实现从表单插入新的消息,另外一个用于发布消息到Redis队列中。方法index用于渲染我们开始Socket.IO客户端的页面,并且当消息到来的时候更新DOM。

控制器的代码如下 :

<?php namespace App\Http\Controllers;
use App\Http\Requests;
use App\Http\Controllers\Controller;
use Request;
use LRedis;
 
class SocketController extends Controller {
	public function __construct()
	{
		$this->middleware('guest');
	}
	public function index()
	{
		return view('socket');
	}
	public function writemessage()
	{
		return view('writemessage');
	}
	public function sendMessage(){
		$redis = LRedis::connection();
		$redis->publish('message', Request::input('message'));
		return redirect('writemessage');
	}
}
第 5 段(可获 2 积分)

在构造函数中设置设置认证系统为guest,这样可以避免客户一直被要求登陆。方法indexwritemessage是非常简单的方法,仅仅用于渲染视图。最重要的是sendMessage方法,在这个方法中,我们使用Redis推送表单输入的消息到消息队列中,然后重新跳转应用到表单页面。

下面是表单视图,没有什么特别的。

@extends('app')
 
@section('content')
    <div class="container">
        <div class="row">
            <div class="col-md-10 col-md-offset-1">
                <div class="panel panel-default">
                    <div class="panel-heading">Send message</div>
                    <form action="sendmessage" method="POST">
                        <input type="text" name="message" >
                        <input type="submit" value="send">
                    </form>
                </div>
            </div>
        </div>
    </div>
 
@endsection
第 6 段(可获 2 积分)

为了使socket能够正常工作,接收消息的页面需要引入一些javascript代码,我们使用了简单的JQuery append函数更新DOM,虽说如此,使用AngularJS更新的话会更有意思一些,在下一篇教程中我们可能会看到如何使用它。现在我们先看看socket页面的源码

socket.blade.php

@extends('app')
 
@section('content')
    <script src="//code.jquery.com/jquery-1.11.2.min.js"></script>
    <script src="//code.jquery.com/jquery-migrate-1.2.1.min.js"></script>
    <script src="https://cdn.socket.io/socket.io-1.3.4.js"></script>
 
    <div class="container">
        <div class="row">
            <div class="col-lg-8 col-lg-offset-2" >
              <div id="messages" ></div>
            </div>
        </div>
    </div>
    <script>
        var socket = io.connect('http://localhost:8890');
        socket.on('message', function (data) {
            $( "#messages" ).append( "<p>"+data+"</p>" );
          });
    </script>
 
 
@endsection
第 7 段(可获 2 积分)

Laravel应用中我们需要做的最后一件事是添加到页面的路由。在routes.php文件中添加下面这些

PHP

Route::get('socket', 'SocketController@index');
Route::post('sendmessage', 'SocketController@sendMessage');
Route::get('writemessage', 'SocketController@writemessage');
所有工作都做完了。你可以启动Redis和NodeJS服务器测试一下我们的应用。当所有的应用都启动之后,打开两个浏览器,一个打开sendmessage页面,另外一个或多个打开socket页面。
第 8 段(可获 2 积分)

现在如果你使用表单提交一个消息的话,这个消息将会传播到所有打开的客户端,并且通过JQuery推送到DOM。这个在Laravel中实现的Socket.IO是非常容易并且稳定的,但是有一些缺点。第一是你需要两个http端口,一个用于PHP服务器,另一个用于node/socket服务器。另一个问题在代码逻辑中。如果你想使用多个频道的话,你必须同时修改NodeJS服务器和Laravel控制器。

在Laravel中使用Socket.IO是非常有趣的,所以可能我会继续更好的学习它,写更多这方面的教程。

本教程中完整的代码可以在 GitHub 找到。

第 9 段(可获 2 积分)

文章评论

访客
麻烦死