React Native中pusher-websocket-react-native的onEvent方法无响应
实时事件推送故障排查(Laravel + React Native + Laravel Websockets)
技术栈
- 后端:Laravel,基于Laravel Websockets实现事件广播
- 前端:React Native,通过Pusher客户端订阅广播频道
后端实现
接口处理逻辑
通过store方法处理请求,验证参数后创建Trip实例并分发EventCreated事件:
public function store(Request $request) { try{ $validator= Validator::make($request->all(), [ 'origin' => 'required', 'originName'=>'required', 'comments' ]); if($validator->fails()){ return $validator->errors(); } $trip= $request->user()->trips()->create($request->only([ 'origin', 'originName', 'comments', ])); EventCreated::dispatch($trip, $request->user()); return $trip; } catch(\Exception $e){ return response()->json(['error'=> $e->getMessage()], 400); } }
事件定义
EventCreated事件实现ShouldBroadcast接口,指定广播到公开频道drivers:
<?php namespace App\Events; use App\Models\Trip; use App\Models\User; use Illuminate\Broadcasting\Channel; use Illuminate\Queue\SerializesModels; use Illuminate\Broadcasting\PrivateChannel; use Illuminate\Broadcasting\PresenceChannel; use Illuminate\Foundation\Events\Dispatchable; use Illuminate\Broadcasting\InteractsWithSockets; use Illuminate\Contracts\Broadcasting\ShouldBroadcast; use Illuminate\Contracts\Broadcasting\ShouldBroadcastNow; class EventCreated implements ShouldBroadcast { use Dispatchable, InteractsWithSockets, SerializesModels; public $trip; private $user; public function __construct(Trip $trip, User $user) { $this->trip = $trip; $this->user = $user; } public $queue = 'default'; public function broadcastOn(): array { return [ new Channel('drivers') ]; } }
React Native前端实现
触发逻辑
通过按钮点击初始化Pusher并订阅频道:
<Button title="订阅频道" onPress={getPusher} />
Pusher客户端配置
const pusher = Pusher.getInstance(); const onEvent = (event: PusherEvent)=>{ console.log(`onEvent> ${event}`) } const onSubscriptionSucceeded = (channelName) => { console.log(channelName) console.log( `onSubscriptionSucceeded: ${channelName}` ); const channel= pusher.getChannel(channelName); if (!channel) { console.log("No Channel"); return } const me = channel.me; console.log(me); } const onError = (message, code, error) => { console.log(`onError: ${message} code: ${code} exception: ${error}`); }; const onSubscriptionError = ( channelName, message, e ) => { console.log(`onSubscriptionError: ${message}, channelName: ${channelName} e: ${e}`); }; const onDecryptionFailure = (eventName, reason) => { console.log(`onDecryptionFailure: ${eventName} reason: ${reason}`); }; const onConnectionStateChange = ( currentState, previousState ) => { console.log( `onConnectionStateChange. previousState=${previousState} newState=${currentState}` ); }; const getPusher = async()=>{ try{ await pusher.init({ apiKey: APP_KEY, cluster: APP_CLUSTER, authEndpoint: "http://127.0.0.1:8000/pusher/broadcasting/auth", port: 6001, onConnectionStateChange, onError, onEvent, onSubscriptionSucceeded, onSubscriptionError, onDecryptionFailure }).catch(error=>console.log(error)); await pusher.subscribe({channelName:'drivers'}); await pusher.connect(); console.log(pusher) } catch(e){ console.log(`ERROR> ${e}`) } }
问题现象
点击按钮后成功订阅drivers频道,但通过Postman调用后端接口触发事件分发时,React Native端的onEvent方法无任何输出,未接收到事件数据。尝试将事件类改为实现ShouldBroadcastNow接口,问题仍存在。
排查与解决步骤
- 确认事件广播名称匹配
Laravel事件默认广播名称为类名的蛇形格式,例如EventCreated对应事件名event_created。修改onEvent回调打印完整事件信息,确认是否监听了正确的事件名:
const onEvent = (event: PusherEvent)=>{ console.log(`事件名: ${event.eventName}, 数据: ${JSON.stringify(event.data)}`); }
- 检查Laravel Websockets服务与队列状态
- 确保
php artisan websockets:serve命令正在运行,访问Laravel Websockets控制台查看是否有事件广播记录 - 若使用
ShouldBroadcast接口,需启动队列 worker:php artisan queue:work;使用ShouldBroadcastNow则无需队列,但需确保事件未被阻塞
- 修正Pusher客户端网络配置
- 真机调试时,
authEndpoint和wsHost需使用电脑的局域网IP(而非127.0.0.1),否则真机无法连接到本地服务 - 本地调试关闭SSL加密,避免证书问题:
await pusher.init({ apiKey: APP_KEY, cluster: APP_CLUSTER, authEndpoint: "http://你的局域网IP:8000/pusher/broadcasting/auth", wsHost: "你的局域网IP", wsPort: 6001, encrypted: false, // ...其他回调 });
- 调整事件广播数据可见性
事件中的$user为私有属性,不会被序列化广播。若需传递用户数据,可改为public属性或自定义广播数据:
// 方法1:改为public属性 public $user; // 方法2:自定义广播数据 public function broadcastWith() { return [ 'trip' => $this->trip, 'user' => $this->user->only('id', 'name') ]; }
- 简化公开频道订阅配置
drivers为公开频道,无需认证,可移除前端配置中的authEndpoint,避免不必要的认证请求干扰:
await pusher.init({ apiKey: APP_KEY, cluster: APP_CLUSTER, wsHost: "你的局域网IP", wsPort: 6001, encrypted: false, // ...其他回调 });
- 手动测试事件广播
通过Laravel Websockets控制台的「Message」功能,手动发送事件到drivers频道:
- 频道名:
drivers - 事件名:
event_created - 数据:
{"trip": {"id": 1, "origin": "测试地址"}}
若前端能收到,说明后端事件触发逻辑有问题;若收不到,说明前端客户端配置存在故障
内容的提问来源于stack exchange,提问作者John Smith
相关产品推荐
相关产品推荐

