拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Symfony Notifier 的 Sendberry 短信桥接组件:DSN 配置、发送原理与版本演进全解析

Symfony Notifier 的 Sendberry 短信桥接组件:DSN 配置、发送原理与版本演进全解析
  • 后端
  • Web框架

【免费下载链接】symfony

The Symfony PHP framework

项目地址:https://gitcode.com/GitHub_Trending/sy/symfony
点击查看免费下载

Sendberry 是 Symfony Notifier 组件为 Sendberry 短信服务平台提供的一体化接入桥(Bridge),本指南将带你完整掌握其 DSN 配置参数、SmsMessage发送流程、底层 HTTP 请求结构、消息校验规则以及 6.1~8.2 各版本的能力演进。读完本文,你既能写出可直接运行的.env配置,也能读懂SendberryTransport源码级实现,并了解如何用测试用例验证桥接行为。

一、桥接组件定位与安装前提

Sendberry 桥接位于 src/Symfony/Component/Notifier/Bridge/Sendberry,属于 Symfony Notifier 生态中众多短信(SMS)桥接之一。从 composer.json 可以看到它的依赖约束:

  • php: >=8.4.1,要求较新的 PHP 运行时;
  • symfony/http-client: ^7.4|^8.0,发送短信依赖 HttpClient 发起 HTTP 请求;
  • symfony/notifier: ^8.2,桥接建立在 Notifier 组件的 Transport 抽象之上;
  • 类型为symfony-notifier-bridge,自动加载命名空间为Symfony\Component\Notifier\Bridge\Sendberry。

因此,要在应用中使用它,至少需要安装 Notifier 与 HttpClient 两个组件,例如:

composer require symfony/notifier symfony/http-client

然后通过symfony/notifier的桥接发现机制加载sendberryscheme。实际发送短信时,Notifier 的Transport接口负责消息分发,而桥接只需要实现supports()与doSend()两个关键方法(见 SendberryTransport.php)。

二、DSN 配置:完整参数与来源

Sendberry 桥接的官方 DSN 示例(来自 README.md)如下:

SENDBERRY_DSN=sendberry://USERNAME:PASSWORD@default?auth_key=AUTH_KEY&from=FROM

各组成部分含义如下表:

DSN 片段说明
USERNAME你在 Sendberry 平台自定义的访问用户名(access name)
PASSWORD与用户名对应的访问密码(access password)
AUTH_KEY平台生成的认证密钥(authentication key)
FROM发件人名称,可以是电话号码或发件人名称(sender name)

其中USERNAME、PASSWORD分别由 SendberryTransportFactory.php 通过基类AbstractTransportFactory的getUser()与getPassword()解析;若缺失会抛出IncompleteDsnException(见 AbstractTransportFactory.php)。

auth_key与from则通过$dsn->getRequiredOption('auth_key')/$dsn->getRequiredOption('from')读取,属于必填查询参数。测试用例 SendberryTransportFactoryTest.php 明确验证了缺少任一参数都会报错:

// missing option: auth_key 'sendberry://username:password@default?from=from' // missing option: from 'sendberry://username:password@default?auth_key=auth_key'

另外,host部分若为字面量default会被置空('default' === $dsn->getHost() ? null : $dsn->getHost()),随后交由setHost()处理,最终回落到SendberryTransport::HOST = 'api.sendberry.com';port同样可显式覆盖。

三、8.2 新增:ssl选项与明文 HTTP 通道

CHANGELOG 记录 8.2 版本引入了一个重要能力:新增sslDSN 选项,用于通过明文 HTTP 发送请求("Add thesslDSN option to send requests over plain HTTP")。

在工厂侧(SendberryTransportFactory.php),构造 Transport 后链式调用了->setSsl($this->getSsl($dsn))。基类getSsl()的实现(AbstractTransportFactory.php)为:

protected function getSsl(Dsn $dsn): ?bool { return null === $dsn->getOption('ssl') ? null : $dsn->getBooleanOption('ssl'); }

即:未提供ssl时返回null;提供时按布尔值解析。在 Transport 侧,AbstractTransport::getHttpScheme()(AbstractTransport.php)决定最终协议:

protected function getHttpScheme(): string { return ($this->ssl ?? static::SSL) ? 'https' : 'http'; }

因此,只要在 DSN 中追加&ssl=0或&ssl=false,即可让桥接改用明文http://访问api.sendberry.com/SMS/SEND端点。这一特性通常用于对接仅提供明文 HTTP 的网关或本地联调环境;生产环境仍默认走 HTTPS(基类默认SSL常量为真)。

四、消息发送流程与底层 HTTP 调用

SendberryTransport只支持SmsMessage。supports()返回$message instanceof SmsMessage(SendberryTransport.php);若在doSend()中收到非SmsMessage,会抛出UnsupportedMessageTypeException。测试 SendberryTransportTest.php 也验证了ChatMessage与DummyMessage均不被支持。

4.1 发件人取值优先级

doSend()的第一步是确定发件人:

$from = $message->getFrom() ?: $this->from;

这与 CHANGELOG 中 6.2 版本的能力一一对应:当SmsMessage定义了from时优先使用消息自身的发件人,否则回退到 DSN 配置的from("UseSmsMessage->fromwhen defined")。这使得同一条 DSN 可以服务多个不同发件人场景。

4.2 发件人格式校验

随后代码用两段正则校验$from(SendberryTransport.php):

  1. 若匹配^[+]+[1-9][0-9]{9,14}$,视为合法的国际格式电话号码(+开头、首位非 0、总长 10~15 位);
  2. 否则要求非空,且仅包含a-zA-Z0-9与空格,即合法的字母数字 Sender ID;
  3. 空字符串或含其他字符都会抛出IncompleteDsnException(分别提示"This phone number is invalid."与"The Sender ID is invalid.")。

4.3 请求端点与 JSON 载荷

实际请求构造如下(SendberryTransport.php):

$endpoint = \sprintf('%s://%s/SMS/SEND', $this->getHttpScheme(), $this->getEndpoint()); $response = $this->client->request('POST', $endpoint, [ 'json' => [ 'from' => $from, 'to' => [$message->getPhone()], 'content' => $message->getSubject(), 'key' => $this->authKey, 'name' => $this->username, 'password' => $this->password, ], ]);

要点:

  • 目标为POST {scheme}://{host}[/:{port}]/SMS/SEND,getEndpoint()会拼接自定义 host/port,缺省时使用api.sendberry.com(AbstractTransport.php);
  • 载荷为 JSON:from、to(数组)、content、key、name、password六个字段,其中to来自SmsMessage::getPhone(),content来自getSubject();
  • 若 HttpClient 本身抛TransportExceptionInterface(网络不可达),会被包装为TransportException("Could not reach the remote Sendberry server.")。

4.4 响应校验与消息 ID

请求返回后按如下规则处理(SendberryTransport.php):

  1. 状态码非 200 时抛出TransportException("Unable to send the SMS.");
  2. 解析 JSON 响应,若status存在且不等于'ok',则把message数组逐行拼接进异常信息再抛出;
  3. 成功时构造SentMessage,并读取ID字段作为消息 ID 写入($sentMessage->setMessageId($responseArr['ID'])),便于后续追踪与对账。

SentMessage的(string)$this形式来自__toString()(SendberryTransport.php),会以sendberry://{endpoint}?from={from}的格式记录发送元信息。

五、消息分发:事件与异常路径

SendberryTransport继承自AbstractTransport,其公开的send()方法(AbstractTransport.php)负责统一的消息分发流程:

  • 未配置事件分发器时直接调用doSend();
  • 配置了EventDispatcherInterface时依次派发MessageEvent(发送前)、SentMessageEvent(成功)或FailedMessageEvent(失败后重抛异常)。

因此,即使桥接本身只实现doSend(),应用仍可无缝接入 Symfony 的事件系统,对发送前、发送成功、发送失败三个阶段做日志、指标或重试处理。

六、版本演进时间线

CHANGELOG 完整记录了该桥接的三个版本节点:

版本变更内容
6.1新增 Sendberry 桥接("Add the bridge"),首次引入SendberryTransport与SendberryTransportFactory
6.2优先使用SmsMessage->from作为发件人("UseSmsMessage->fromwhen defined")
8.2新增sslDSN 选项,支持通过明文 HTTP 发送请求

需要说明:仓库当前 composer.json 要求symfony/notifier: ^8.2、symfony/http-client: ^7.4|^8.0,即当前形态面向 8.x 分支;6.x 时代的 API 结构(SmsMessage::getFrom()、auth_key/from必填项等)在 8.2 中仍然延续,并叠加了ssl选项的新能力。

七、测试验证与自定义 host 场景

仓库内的两组测试可帮助理解桥接行为边界:

  • SendberryTransportTest.php:验证sendberry://api.sendberry.com?from=from的字符串表示、仅支持SmsMessage、拒绝ChatMessage与DummyMessage;
  • SendberryTransportFactoryTest.php:验证 scheme 解析(sendberry://user:password@host.test?auth_key=auth_key&from=%2B0611223344可创建传输、其他 scheme 报UnsupportedSchemeException)、必填项缺失报错、以及缺少 user 的IncompleteDsnException场景。

其中supportsProvider()里出现sendberry://api_key@default?from=%2B0611223344这类无 user/password 仍通过的用例,说明工厂在supports()阶段只做 scheme 匹配,真正的凭据完整性检查推迟到create()/发送时完成。

若需对接 Sendberry 的测试沙箱或自定义网关,可在 DSN 中显式指定 host 与 port,例如:

SENDBERRY_DSN=sendberry://user:pass@sandbox.example.com:8080?auth_key=KEY&from=+8613800138000&ssl=0

其中+8613800138000这类带+的值在 DSN 中需做 URL 编码(%2B),如测试用例所示。

八、快速上手示例

在 Symfony 应用中使用 Sendberry 发送短信的最小路径:

  1. 安装依赖:

    composer require symfony/notifier symfony/http-client
  2. 在.env中配置 DSN:

    SENDBERRY_DSN=sendberry://USERNAME:PASSWORD@default?auth_key=AUTH_KEY&from=FROM
  3. 通过Notifier服务发送SmsMessage:

    use Symfony\Component\Notifier\Notifier; use Symfony\Component\Notifier\NotifierInterface; use Symfony\Component\Notifier\Recipient\Recipient; /** @var NotifierInterface $notifier */ $notifier->send( new SmsMessage('+8613800138000', 'Hello from Symfony!', '+8613900139000'), new Recipient('+8613800138000'), );

    若第三个参数(from)留空,桥接会自动使用 DSN 中的FROM;指定后则以消息级from为准(对应 6.2 行为)。

  4. 调试时可用MockHttpClient替换真实客户端(如测试所示),在不触网的情况下断言请求载荷与错误分支。

综上,Sendberry 桥接虽然代码量小,却完整覆盖了 DSN 解析、消息类型约束、发件人校验、HTTP 调用与错误归一化等 Notifier 桥接的标准范式,是理解 Symfony Notifier 传输层实现的上佳样例。

  • 后端
  • Web框架

【免费下载链接】symfony

The Symfony PHP framework

项目地址:https://gitcode.com/GitHub_Trending/sy/symfony
点击查看免费下载

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

返回列表