下面由Laravel教程栏目给大家介绍laravel-echo-server广播服务搭建,希望对需要的朋友有所帮助!
动机
当前项目中很多场景采用 Redis 队列和定时任务来处理执行时间较长的任务,这些任务执行的状态和执行结果只能通过前端重新发送请求获取。
目标
为了优化程序体验,让用户尽可能早的关注到任务执行结果,我们评估了各种方案。为了降低前后端的沟通成本避免重复造轮子,我们决定采用 Laravel 框架内置的广播功能。
选择服务
官方推荐采用 pusher 来搭建应用,pusher 的好处是搭建起来非常简单。但考虑到是国外的服务,存在访问稳定性风险;且目前项目规模较小,于是尝试自己搭建 Websocket 服务,使用的就是 Laravel 框架官方提到的 tlaverdure/laravel-echo-server 项目。
laravel-echo-server 服务特点
这个项目的使用方法可以直接去他们的 github 页面 获得,我们看中的几点如下:
- 可通过 Redis 的发布订阅功能来获取事件信息并广播出去,这点的效率要高于向 pusher 的 HTTP API 发送推送请求;
- 同时兼容 pusher 的 HTTP API ,如果一些服务无法通过 Redis 发布事件,则可以采用这种模式推送事件;
搭建 Websocket 服务
我们一开始使用了 oanhnn/laravel-echo-server 这个镜像来启动容器,在调试过程中发现这个服务并不稳定,Node 的服务会在异常时直接退出,这是我们碰到的第一个坑。为了快速解决这个问题,我们再这个镜像基础上加入了 supervisor 来负责进行服务进程的退出后重启的任务,并做成了我们自己的镜像。
Redis 订阅
在试用 Redis 订阅时,除了常规的数据库地址和密码等参数以外,key 前缀是我们碰到的又一个坑,对应在 laravel-echo-server 服务中的 文件中的 keyPrefix 配置项,一开始没有找到正确的方法,无论怎么配置都不对。后来发现如果想知道要广播事件的程序当前的 Redis key 前缀是什么,就在 tinker 中执行以下脚本即可。
# php artisan tinkerconfig('');
Nginx 代理
由于生产环境采用了 HTTPS 协议,所以需要给服务增加证书,但因为我是 Node 小白,没有 Node 程序使用证书的配置经验,所以一轮尝试之后基本上放弃了,之后采用了 Nginx 代理的方式使用证书,经过几轮尝试,终于配置成功。
server {
listen port;
server_name your-domain;
ssl on;
ssl_certificate path-to-pem;
ssl_certificate_key path-to-key;
ssl_session_timeout 5m;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
location /socket.io {
proxy_pass http://container-name:6002;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
}}
私有/出席频道授权
Laravel 广播将频道分为:公共、私有和出席(我可能翻译的不对,请指正),其中后两者是需要授权访问。我们需要用到的是私有频道,只有经过授权的人才能从前端订阅我们的事件。这也是我们遇到的一个坑。
经我们观察和源码阅读,发现 laravel-echo 的整体授权过程是:
- 前端程序先向 laravel-echo-server 服务发送一个 HTTP POST 请求;
- laravel-echo-server 根据配置中
authEndpoint
和authHost
这两项,向应用服务器发送一个 HTTP POST,POST 数据是 channel 名字,同时透传 header 中的 Authorization 数据; - laravel-echo-server 会根据应用服务器的响应来判断授权结果,如果应用服务器响应的是非 HTTP 200 状态,就说明发生了错误,授权失败。
我们在实践中遇到两个问题。第一个问题是,我们项目的授权守门逻辑并非 laravel 默认的,所以默认的 Broadcast::routes()
所引入的路由无法直接使用。发现问题后,我们重新加入了我们自己的授权路由,并配置到 的 authEndpoint
配置项中。
另一个问题是,我们没有采用标准的 RESTFul 协议规则:响应对应的 HTTP Code 来描述错误状态。致使 laravel-echo-server 即便在授权失败的时候也不能发现问题并反馈给前端程序,情况类似下图:
迟早还是要还债的…
总结
这个功能开发的,没有当初想的那么顺利,主要的问题有以下几点:
- laravel-echo-server 没有预想的那么健壮,以后有时间还得找找替代方案,貌似也有用 swoole 做的项目,可以尝试一下;
- 预先忘记考虑到 SSL 的问题,导致发布时临时处理得手忙脚乱;
- laravel-echo-server 和 laravel-echo 本身都是很小的项目,遇到问题应该优先考虑去分析其代码减少尝试的时间。