必须改用 alibabacloud/sdk 并配置 SwooleHandler,因旧版 SDK 基于同步 cURL 与 Webman 协程环境冲突,导致签名错乱、内存泄漏等问题;需单例复用客户端、分离配置、严格 JSON 编码模板参数。

Webman 项目里直接用阿里云老版 SDK(aliyun-php-sdk-core + aliyun-php-sdk-dysmsapi)会报错或不兼容,根本原因是其依赖的 RequestCore 和签名逻辑与 Webman 的 PSR-7 / Swoole 环境冲突,且已停止维护。必须改用官方推荐的现代 SDK:alibabacloud/sdk。
为什么不能用旧版 aliyun-php-sdk-core
旧版 SDK 基于同步 cURL、全局函数和静态类设计,与 Webman 的协程环境(Swoole)不兼容——它会在长连接中复用连接句柄,导致并发调用时请求头/签名混乱,常见错误包括:
-
InvalidAccessKeyId.NotFound(实际 AK 是对的,但签名被污染) -
SignatureDoesNotMatch(时间戳或参数顺序在并发下错乱) - 进程内存泄漏,
php-fpm模式下看似正常,但切换到swoole后频繁超时或崩溃
必须用 alibabacloud/sdk 并禁用 Guzzle 默认 Handler
新版 alibabacloud/sdk 基于 PSR-18 和 Guzzle,但 Webman 默认使用 Swoole 驱动的 HTTP 客户端,而 Guzzle 默认走 cURL。若不显式替换,会引发协程阻塞。正确做法是:
- 安装:
composer require alibabacloud/sdk - 初始化客户端时,传入 Webman 自带的
SwooleHttpHandler(或自定义 PSR-18 兼容 handler) - 避免在
onWorkerStart外重复 new Client,应单例复用
示例初始化代码(放在 app/Service/SmsService.php):
立即学习“PHP免费学习笔记(深入)”;
use AlibabaCloud\Client\AlibabaCloud;
use AlibabaCloud\Client\Exception\ClientException;
use AlibabaCloud\Client\Exception\ServerException;
use AlibabaCloud\Dysmsapi\V20170525\SendSmsRequest;
class SmsService
{
private static $client;
public static function getClient()
{
if (self::$client === null) {
// 使用 Webman 的 Swoole HTTP handler(需确保已启用 swoole_http_client)
$handler = new \GuzzleHttp\Handler\SwooleHandler();
$client = new \GuzzleHttp\Client(['handler' => $handler]);
AlibabaCloud::init([
'guzzle' => ['handler' => $handler]
]);
AlibabaCloud::accessKeyClient(
config('sms.access_key_id'),
config('sms.access_key_secret')
)->regionId('cn-hangzhou')
->asDefaultClient();
self::$client = AlibabaCloud::getDefaultClient();
}
return self::$client;
}
public static function send($phone, $templateCode, $params)
{
try {
$request = new SendSmsRequest([
'PhoneNumbers' => $phone,
'SignName' => config('sms.sign_name'),
'TemplateCode' => $templateCode,
'TemplateParam' => json_encode($params, JSON_UNESCAPED_UNICODE),
]);
$response = AlibabaCloud::rpc()->execute($request);
return $response->toArray();
} catch (ClientException | ServerException $e) {
throw new \RuntimeException($e->getErrorMessage());
}
}
}
Webman 配置项必须分离敏感信息
AK/签名/模板等不能硬编码在代码里,Webman 的配置机制支持多环境分层。应在 config/sms.php 中定义:
return [
'access_key_id' => env('ALIYUN_SMS_ACCESS_KEY_ID', ''),
'access_key_secret' => env('ALIYUN_SMS_ACCESS_KEY_SECRET', ''),
'sign_name' => env('ALIYUN_SMS_SIGN_NAME', ''),
'region_id' => 'cn-hangzhou',
];
并在 .env 中填写:
ALIYUN_SMS_ACCESS_KEY_ID=your_aki_xxx ALIYUN_SMS_ACCESS_KEY_SECRET=your_aks_xxx ALIYUN_SMS_SIGN_NAME=你的签名
注意:access_key_secret 绝对不能出现在 Git 历史中;Webman 的 env() 加载默认不缓存,建议上线前用 php webman optimize:config 编译配置提升性能。
模板变量必须严格 JSON 编码且 UTF-8 无 BOM
阿里云接口要求 TemplateParam 是标准 JSON 字符串,且键名必须与模板中定义的占位符完全一致(大小写敏感),值必须是字符串类型。常见翻车点:
- 直接传数组给
TemplateParam→ 报错InvalidJSONFormat - 用
json_encode($arr)但未加JSON_UNESCAPED_UNICODE→ 中文变\u4f60\u597d,签名校验失败 - 模板里写的是
{code},却传了['CODE' => '123']→ 返回TemplateParameterMismatch
务必校验模板内容与传参字段名是否一字不差,调试时可先用阿里云控制台「API 调试」功能验证参数组合是否合法。
最易被忽略的是:Webman 在 Swoole 模式下,AlibabaCloud::getDefaultClient() 不是线程安全的,多个协程并发调用时若未提前初始化或未复用单例,会导致内部状态错乱。所有短信调用入口必须经过封装后的 SmsService::send(),禁止在控制器里临时 new Request 或手动调用 rpc()->execute()。



















