internal-services/service-sdk

Reusable PHP clients for internal HTTP services.

Maintainers

Package info

github.com/ZhaoYifei9/internal-service-sdk

pkg:composer/internal-services/service-sdk

Transparency log

Statistics

Installs: 164

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v0.4.0 2026-07-24 15:38 UTC

This package is auto-updated.

Last update: 2026-08-05 10:59:38 UTC


README

供各国家 PHP 业务项目复用的内部 HTTP 客户端,兼容 PHP 7.4。当前包含:

  • 固定九行 Canonical Request 的 X-Internal-* HMAC-SHA256 签名;
  • data-mid 事件类型、稳定事件 ID、事件工厂、订单上下文脱敏、批量结果及高阶上报门面;
  • data-mid 单事件和批量事件 HTTP 上报;
  • service-notification FCM 设备注册;
  • toolbox-service 飞书 V2 告警、告警目录及旧自定义消息兜底;
  • AJ 设备与事件 DTO、JSON 客户端及可配置重试;
  • 支持服务身份与 Toolbox Actor/Scopes 的原始 Signed HTTP 请求;
  • 可替换的 TransportInterface,以及可选 Swoole、Guzzle Transport。

包不读取环境变量、不访问 Redis 或数据库。调用方负责注入具体调度器、去重存储、告警 ID、业务 Payload 与运行配置; SDK 统一调度/去重接口、上报生命周期和协议客户端。Secret 不得写入仓库或日志。

安装

包发布在 Packagist,可直接安装:

composer require internal-services/service-sdk:^0.4

无需配置 Composer VCS Repository、GitHub Token 或 SSH Deploy Key。

data-mid

use Internal\ServiceSdk\DataMid\DataMidClient;
use Internal\ServiceSdk\DataMid\EventFactory;

$client = new DataMidClient([
    'base_url' => getenv('MID_GATEWAY'),
    'country_code' => getenv('COUNTRY_CODE'),
    'client_id' => getenv('MID_CLIENT_ID'),
    'secret' => getenv('MID_SECRET'),
    'timeout' => 10,
]);

$events = new EventFactory('NG');
$event = $events->applicationSubmitted(
    '42',
    '5001',
    '业务手机号',
    'ORDER-001',
    'PRODUCT-01',
    'Quick Loan'
);

$response = $client->reportEvent($event->payload());

EventFactory 统一生成协议字段、事件时间、稳定 event_id 和生产端去重 Key;EventTypeEventIdOrderContext 也可独立使用。reportEvent()reportBatch() 返回 HttpResponse。需要推进批处理断点时使用 reportBatchResult(),只有 BatchReportResult::isComplete($expected)true 才表示全部接收。

推荐业务入口使用 DataMidReporter:它统一命名事件、异步派发、生产端去重租约、失败释放和批量完整接收判断。 国家项目用 CallableDispatcher 适配协程,以 DedupStoreInterface 适配 Redis;SDK 自身不依赖具体框架或缓存实现。

内部管理端请求

Toolbox/BFF 调用 data-mid、service-notification 或 service-short-link 管理端时,使用 SignedHttpClient 对实际发送的 Method、Path + Query 和原始 Body 字节签名,并通过 InternalRequestContext 传递已经由 Toolbox 鉴权的操作人和权限。SDK 不读取 Laravel Request、用户模型或 权限数据,也不会自行授予 Scope。

use Internal\ServiceSdk\Auth\InternalRequestContext;
use Internal\ServiceSdk\Http\GuzzleHttpTransport;
use Internal\ServiceSdk\Http\QueryString;
use Internal\ServiceSdk\Http\SignedHttpClient;

$client = new SignedHttpClient([
    'base_url' => getenv('DATA_MID_BASE_URL'),
    'client_id' => getenv('DATA_MID_CLIENT_ID'),
    'secret' => getenv('DATA_MID_CLIENT_SECRET'),
    'timeout' => 10,
], new GuzzleHttpTransport());

$context = new InternalRequestContext(
    'operator-id',
    'operator@example.com',
    'mid.rules.read,mid.rules.edit',
    'request-id'
);
$path = QueryString::append('/admin/v1/rules', ['country_code' => 'NG']);
$response = $client->request('GET', $path, '', $context);

Idempotency-Key 等不属于九行 Canonical 的协议 Header 可以通过第五个参数传入; X-Internal-*X-Request-Id 禁止从附加 Header 覆盖。

通知设备注册

use Internal\ServiceSdk\Notification\DeviceRegistration;
use Internal\ServiceSdk\Notification\NotificationDeviceClient;

$client = new NotificationDeviceClient([
    'base_url' => getenv('NOTIFICATION_SERVICE_URL'),
    'client_id' => getenv('NOTIFICATION_SERVICE_CLIENT_ID'),
    'secret' => getenv('NOTIFICATION_SERVICE_SECRET'),
    'timeout' => 5,
]);

$client->registerDevice(new DeviceRegistration(
    'install-uuid',
    'NG',
    '5001',
    DeviceRegistration::PLATFORM_ANDROID,
    '当前 Token(至少 20 字节)',
    '2026-07-24T12:00:00.000000+01:00',
    '可选 GAID'
));

DeviceRegistration 在发出请求前统一规范国家、平台和可选 AAID,并校验通知服务的完整字段、长度和 RFC 3339 时间契约。原有 register($installUuid, $payload) 作为低层兼容入口继续保留。

toolbox 飞书告警

use Internal\ServiceSdk\Toolbox\AlertCatalog;
use Internal\ServiceSdk\Toolbox\FeishuAlertClient;
use Internal\ServiceSdk\Toolbox\FeishuNotifier;

$client = new FeishuAlertClient([
    'base_url' => getenv('FEISHU_BASE_URL'),
    'app_name' => 'country-loan-api',
    'environment' => getenv('APP_ENV'),
    'timeout' => 10,
]);

$notifier = new FeishuNotifier($client, new AlertCatalog([
    'SYSTEM_ERROR' => [
        'id' => 'COUNTRY-SYSTEM-ERROR',
        'description' => '系统错误',
    ],
]));
$notifier->notify('SYSTEM_ERROR', [
    'message' => ['error' => 'example'],
], 1);

toolbox 返回 code=0 表示已发送,code=200 表示规则判定后跳过,两者都属于正常受理。V2 调用失败时, FeishuNotifier 可自动调用旧自定义消息接口兜底,且不会把原始业务 Payload 复制到兜底内容。

AJ 事件客户端

AjClient 统一 /api/device/ma/api/event 的 JSON 请求、超时、响应解析和有限重试;协程项目可注入非阻塞 Sleeper。AjEvent 强制调用方显式传入 clientVersion,避免复制国家代码时沿用错误值。订单状态映射、首复贷、 风控判断、SQL、Redis 业务幂等和延迟任务仍属于业务项目。

请求上下文与测试

构造函数支持注入 Transport、时钟、Nonce 和 Request ID Resolver。Hyperf 项目可用 Resolver 传递当前请求 ID; 单元测试使用 Fake Transport 验证完整方法、URL、正文和签名,不需要启动公共服务。

ext-swooleguzzlehttp/guzzle 均为按运行时选择的可选依赖:原有 Hyperf/Swoole 项目可以继续使用默认 SwooleHttpTransport;Laravel 等项目显式注入 GuzzleHttpTransport,安装 SDK 不再强制要求 Swoole 扩展。

composer install
composer test