使用Laravel调用SignalWire API发送SMS时出现send()空对象调用错误
排查Laravel中SignalWire Relay Client发送SMS时"Call to a member function send() on null"错误
错误原因
这个错误的核心是SignalWire Relay Client的WebSocket连接未成功初始化,Connection.php中的$_ws属性为null,导致调用send()方法时抛出致命错误。具体诱因包括:
- 客户端未完成WebSocket连接就直接调用短信发送方法:SignalWire Relay Client是异步建立连接的,你的代码在实例化客户端后立即调用
send(),此时连接还未建立完成,$_ws还未被赋值。 - 项目ID或Token配置错误:凭证无效会导致连接建立失败,
$_ws始终为null。 - 网络限制:服务器防火墙/安全组阻止了到SignalWire Relay服务(wss://relay.signalwire.com)的WebSocket(443端口)出站请求。
- 未处理异步逻辑的状态:Laravel的Web请求会在脚本执行完毕后终止,若未使用队列或保持事件循环,异步连接和发送逻辑无法完成。
解决方法
1. 修正代码:等待连接成功后再发送短信
SignalWire Client需要先完成连接才能执行操作,修改代码使用connect()的回调确保连接就绪:
use SignalWire\Relay\Client; $client = new Client([ 'project' => 'your_project_id', // 替换为真实项目ID 'token' => 'your_auth_token' // 替换为真实Token ]); $params = [ 'context' => 'office', 'from' => '+1XXXXXXXXX', // 必须是你的SignalWire号码 'to' => '+1XXXXXXXXX', // 目标接收号码 'body' => 'Welcome at SignalWire!' ]; // 先等待连接成功 $client->connect()->done(function() use ($client, $params) { Log::info('Connected to SignalWire, sending SMS..'); $client->messaging->send($params)->done( function ($sendResult) { if ($sendResult->isSuccessful()) { Log::info('SMS queued successfully!'); echo 'success'; } else { Log::warning('Error sending SMS!'); echo 'error'; } }, function($error) { Log::error('SMS send failed: ' . $error->getMessage()); echo 'send_error'; } ); }, function($error) { Log::error('SignalWire connection failed: ' . $error->getMessage()); echo 'connect_error'; }); // CLI环境下必须调用,保持事件循环运行 $client->loop();
2. 验证凭证正确性
确认project和token是从SignalWire控制台获取的有效值,无拼写错误或格式问题。
3. 检查网络连通性
测试服务器是否能访问SignalWire的Relay服务:
# 使用wscat测试WebSocket连接(先安装npm install -g wscat) wscat -c wss://relay.signalwire.com
若连接失败,联系服务器管理员开放443端口的WebSocket出站权限。
4. Web环境下使用Laravel队列
如果是在Web请求中发送短信,直接执行异步逻辑会因请求终止而失败,将发送逻辑封装到Laravel队列任务中:
- 创建队列任务:
php artisan make:job SendSignalWireSms
- 在任务类中编写发送逻辑:
// app/Jobs/SendSignalWireSms.php namespace App\Jobs; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Foundation\Bus\Dispatchable; use Illuminate\Queue\InteractsWithQueue; use Illuminate\Queue\SerializesModels; use SignalWire\Relay\Client; use Illuminate\Support\Facades\Log; class SendSignalWireSms implements ShouldQueue { use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; protected $params; public function __construct(array $params) { $this->params = $params; } public function handle() { $client = new Client([ 'project' => config('services.signalwire.project'), 'token' => config('services.signalwire.token') ]); $client->connect()->done(function() use ($client) { $client->messaging->send($this->params)->done( function ($sendResult) { if ($sendResult->isSuccessful()) { Log::info('SMS queued successfully!'); } else { Log::warning('Error sending SMS!'); } }, function($error) { Log::error('SMS send failed: ' . $error->getMessage()); } ); }, function($error) { Log::error('SignalWire connection failed: ' . $error->getMessage()); }); $client->loop(); } }
- 在控制器中调度任务:
use App\Jobs\SendSignalWireSms; // ... $params = [ 'context' => 'office', 'from' => '+1XXXXXXXXX', 'to' => '+1XXXXXXXXX', 'body' => 'Welcome at SignalWire!' ]; SendSignalWireSms::dispatch($params);
5. 更新依赖包
确保使用最新版的SignalWire Relay Client:
composer update signalwire/signalwire
内容的提问来源于stack exchange,提问作者prem chand
相关产品推荐
相关产品推荐

