由于再做一个课程大作业,想要实现一个web私聊的系统,于是去google & baidu 搜索了很多文章来看,但是对于初入门的我并不是很了解其体系架构以及laravel 与 pusher之间的联系,laravel的官方文档也只是告诉怎么用,并没有一个详细的解释,于是头疼了一个星期。接下来就说说我是怎么实现这个功能的。
ps. 这个只是我自己这么觉得。。不一定是对的,但是功能是可以实现的
先上图,此图是我对其理解。
由图可以看到 pusher 在整个交互中处于laravel 之下客户端之上的中间层次。
- 客户端Client1想要发送信息给Client2,于是通过post一个chatData{fromid,toid,msg} 到服务器去处理。
- laravel通过路由交给
chatController@DeliverMessage
处理。 - 在 chatController@DeliverMessage 中,新建事件
chatMessageEvent
并使用event()
这个功能发布至pusher 。 - pusher 推送消息至Client2,Client2 通过监听相应 channel 来获取信息。
以上是laravel pusher的大致流程。
ps.Pusher 是通过 channel 来指定要发送的数据发送到哪儿的,比如Client1创建了一个叫做chat.1的通道,Client2想要发送msg到Client1,pusher就会把消息通过chat.1这个通道广播出去,于是Client1就监听到了信息。
pps.我的解决方案是为每个用户开一个channel,以id区分,只需要广播到相应频道即可接收信息。
下面来讲讲具体实现,在我的大作业上,我是通过laravel5.5 + vue +axios + pusher
实现的。
另外由于我的分工是写后端的,所以对于vue并不很了解,因此vue端只贴代码,具体vue中的操作请参照vue官方文档。
客户端通过vue实现,其所有文件在 你创建的项目\resources\assets\js
下
后台文件自然是在 你创建的项目\app
下
- 准备工作
后台
composer require pusher/pusher-php-server
去pusher官网申请账号(似乎需要科学上网)
得到
PUSHER_APP_ID=
PUSHER_APP_KEY=
PUSHER_APP_SECRET=
//填入.env中 并更改广播驱动为pusher 默认队列为sync
BROADCAST_DRIVER=pusher
QUEUE_DRIVER=sync
前端
cnpm install pusher-js --save
cnpm install laravel-echo --save
- 客户端 post ChatData 到 服务器。
postChatData(){
axios.post('/chat',{
from:id,
to:'1', /*这里是因为页面没有写获取到对方id的方法,所以暂时硬编码进去以便测试*/
msg:'This is a chat data.',
}).then(function(response){
console.log(response.data);
});
}
- 服务端 Route 、Controller 、Event 、Model
php artisan make:controller chatController
来创建Controller
//你创建的项目\routes\web.php
Route::post('/chat','chatController@deliver');
//chatController@deliver
public function deliver(Request $request){
$from=$request->from;
$to=$request->to;
$msg=$request->msg;
/* 这里是因为上面vue中发送给谁硬编码了,所以在这里通过判断更改*/
if($from===1) $to='2';
else $to='1';
$cmsg=new chatMessage;
$cmsg->fid=$from;
$cmsg->tid=$to;
$cmsg->msg=$msg;
$cmsg->save();
event(new chatMessageEvent($cmsg));
return response()->json(['from' => $from,'to'=>$to,'msg'=>$msg]);
}
php artisan make:migration chat_message_table
\\在创建的chat_message_table文件中
public function up(){
Schema::create('chat_messages', function (Blueprint $table) {
$table->increments('id');
$table->integer('fid');
$table->integer('tid');
$table->text('msg');
$table->timestamps();
});
}
php artisan make:model chatMessage
// App\chatMessage.php
class chatMessage extends Model
{
protected $table = 'chat_messages';
protected $primaryKey='id';
protected $fillable = [
'fid','tid','msg',
];
}
php artisan make:event chatMessageEvent
/* App\Events\chatMessageEvent.php
详细信息见laravel 广播 官方文档*/
...
use App\chatMessage;
//注意 这里需要自己继承 ShouldBroadcast 接口
class chatMessageEvent implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $chatMessage; //这是广播的内容
public function __construct($chatMessage) {
$this->chatMessage=$chatMessage;
}
public function broadcastOn() {
return new Channel('chat.'.$this->chatMessage->tid);
}
}
- 客户端接受消息
\\bootstrap.js
...
import Echo from 'laravel-echo'
window.Pusher = require('pusher-js');
window.Echo = new Echo({
broadcaster: 'pusher',
key: 'xxxxxx', //之前准备时得到的key
cluster:'ap1', //在pusher中选择的服务器
encrypted:true //是否加密
});
//在你的vue文件中 获取到自己的id后 创建监听
window.Echo.channel('chat.'+id)
.listen('chatMessageEvent',(data)=>{
console.log(data);
/*返回是否接收信息 此处同样需要定义路由
为了能够解决离线问题,我选择在接收到后返回一个收到信息
并删除数据库中此条记录
在用户再次登陆时区数据库中数据发送
*/
axios.post('/respchat',{
hasReceived:true,
id:data.chatMessage.id,
}).then(function(response){
console.log(response.data);
});
});
至此,你可以通过创建用户登录获取id来创建channel 发送并接受pusher所推送的信息。
第一次写这类文章,难免有所疏漏或错误,希望看到这篇文章的大神们能够指出,万分感谢!