我用Swoft 2.0搭了个共享API平台,支持Vue/React/小程序一键接入
前言
做公益这件事,我走了好多年。中间有过委屈,有过难,甚至看着自己搭建的平台,明明能帮人,却因"不会吆喝"而少有人问津时,也会陷入迷茫。但每当想起乡镇里,有人为了赶一趟班车,天不亮就守在路边;残障朋友想找份能做的活,却被大平台的门槛挡在门外;还有那些假期里,为买不到票、怕堵车而发愁的乡亲们,我又觉得这件事必须得做下去。
——摘自《七家坡的"摆渡人"》
作为一名在PHP领域深耕近20年的后端工程师,我一直在思考:如何用技术力量帮助更多人,同时又能让技术实现可持续发展?本文将分享我基于Swoft 2.0框架构建共享API平台的实践经验。
项目背景
我的共享API平台目前已经支撑了多个公益项目:
-
七家坡基层互助站 (lo.lck.yn.cn/) 提共基于用户当前位置(查询、发布)拼车、运营(车辆、路线)信息等便民服务
-
AI合集 (ai.lck.yn.cn/) 基于AI的(含八字算命,将持续增加更多服务)传统文化服务
这些项目虽然面向不同场景,但都需要相同的底层能力:用户认证、地理定位、支付、数据存储等。为了避免重复造轮子,我决定构建一个共享API平台,让所有项目都能快速接入这些通用能力。
技术选型:为什么选择Swoft 2.0?
在选型时,我对比了多个PHP框架:
| 框架 | 协程支持 | 微服务 | 学习成本 | 性能 |
|---|---|---|---|---|
| Laravel | 无 | 无 | 低 | 中 |
| Hyperf | 有 | 有 | 中 | 高 |
| Swoft 2.0 | 有 | 有 | 中 | 高 |
最终选择Swoft 2.0的原因:
- 成熟的协程支持:基于Swoole扩展,提供原生协程能力,性能接近Go语言
- gRPC原生支持:内置gRPC支持,可与任何语言无缝对接
- 微服务架构:内置RPC服务注册与发现,完美契合我的分布式架构需求
- 注解驱动:类似Spring Cloud的注解机制,代码简洁优雅
- 完善的生态:内置连接池、AOP、任务调度等企业级功能
关于框架选择的真实思考
Swoft 2.0的现状:
- 官方早已停止维护,官网已无法访问
- 基本查不到相关资料,社区支持很少
- 很多功能文档缺失,需要自己摸索
为什么还是选择了它?
- 协程性能优势:Swoole扩展的性能优势难以替代
- 架构设计优秀:微服务、RPC、注解机制的设计理念先进
- 自主掌控:既然官方不维护,我就自己维护
填坑之路:
- 很多功能的实现方案,AI都无法给出正确答案
- 每个坑都花了超过一周的时间去研究、测试、验证
- 通过理解作者意图、结合实战经验、深入底层源码,最终全部实现
给后来者的建议: 技术选型不要盲目追求"官方维护",关键是否适合你的场景。 框架只是工具,你的技术积累和解决问题的能力才是核心。
架构设计
整体架构
┌──────────────────────┐
│ 前端应用层 │
│ ┌────────┐┌────────┐│
│ │七家坡 ││AI站点 ││
│ └────────┘└────────┘│
└──────────────────────┘
│
▼
┌──────────────────────┐
│ API网关层 │
│ Gateway │
│ - JWT认证 │
│ - 权限控制 │
│ - 限流 │
│ - 日志审计 │
└──────────────────────┘
│
▼
┌──────────────────────┐
│ 微服务层 │
│ ┌────┐┌────┐┌────┐│
│ │Traf││Stay││Admi││
│ │fic ││ ││n ││
│ └────┘└────┘└────┘│
└──────────────────────┘
│
▼
┌──────────────────────┐
│ 数据存储层 │
│ ┌────┐┌────┐┌────┐│
│ │MyS ││Redi││支付││
│ │QL ││s ││接口││
│ └────┘└────┘└────┘│
└──────────────────────┘
服务拆分
根据业务领域,我将服务拆分为以下模块(端口为示意配置,实际部署时可自定义):
网关层:
| 服务 | 职责 | 端口 |
|---|---|---|
| gateway | API网关,负责认证、路由、限流、域名授权 | 80 |
微服务层:
| 服务 | 职责 | 包含的子服务 |
|---|---|---|
| login | 登录服务 | 登录 |
| user | 用户服务 | 用户、地址等 |
| code | 验证服务 | 邮箱验证、短信验证(已测试通过) |
| category | 分类服务 | 分类 |
| traffic | 交通服务 | 拼车、运营(岗位信息) |
| stay | 住宿服务 | 小屋(民宿) |
| aigc | AI合集服务 | 八字取名等AI服务 |
| pay | 支付服务 | 订单、支付回调 |
共 8个微服务,每个服务下可能有1或多个子服务。
核心功能实现
1. API网关设计
网关是整个系统的入口,负责:
- JWT认证:基于
Swoft\Auth组件实现,支持token自动刷新 - 域授权机制:根据请求来源域名进行授权控制
- 本地开发友好:localhost/127.0.0.1等本地域名默认已授权
- 权限控制:通过中间件拦截未授权请求
- 服务路由:将请求转发到对应的微服务
- 限流保护:使用
Swoft\Limiter防止接口滥用 - 文档生成:自动生成Swagger文档
网关配置示例(config/beans.php):
return [
'userAuth' => [
'class' => Swoft\Auth\Manager::class,
'name' => 'user',
'language' => 'zh',
'ttl' => 7200, // token有效期2小时
'refreshTtl' => 2592000, // 刷新token有效期30天
],
'jwtAuth' => [
'class' => Swoft\Auth\Parser\JWTAuthParser::class,
]
];
Token自动刷新机制:
// 中间件中实现token自动刷新
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
{
$token = $this->jwtAuth->parse($request);
$payload = $token->payload();
// 检查token是否即将过期(剩余时间小于10分钟)
if ($payload['exp'] - time() < 600) {
$newToken = $this->auth->refreshToken($token);
// 在响应头中返回新token
return $handler->handle($request)->withHeader('X-New-Token', $newToken);
}
return $handler->handle($request);
}
2. 地理位置查询优化(LBS)
顺风车和民宿服务都需要根据用户位置查询附近信息。这是典型的地理围栏查询场景。
优化前的问题
传统使用HAVING计算距离的方式效率低下:
SELECT *,
(6371 * ACOS(
COS(RADIANS(lat)) * COS(RADIANS(24.88)) *
COS(RADIANS(lng) - RADIANS(102.83)) +
SIN(RADIANS(lat)) * SIN(RADIANS(24.88))
)) AS distance
FROM sys_carpooling
HAVING distance < 10
ORDER BY distance
问题:
- 每次查询都要计算全表距离,性能极差
- 无法使用索引,随着数据量增加性能急剧下降
优化方案
采用边界框预过滤 + 空间索引的双重优化策略:
SELECT *,
ST_Distance_Sphere(
location,
ST_GeomFromText('POINT(102.83 24.88)')
) AS distance
FROM sys_carpooling
WHERE lat BETWEEN 24.01 AND 25.75
AND lng BETWEEN 101.91 AND 103.75
AND ST_Distance_Sphere(
location,
POINT(102.83, 24.88)
) <= 10000
ORDER BY distance
LIMIT 20
优化要点:
- 添加空间索引:
ALTER TABLE sys_carpooling
ADD COLUMN location POINT NOT NULL COMMENT '位置坐标' AFTER lat,
ADD SPATIAL INDEX idx_location (location);
- 范围级别参数化:
$rangeMap = [
1 => 10, // 10公里
2 => 50, // 50公里
3 => 100, // 100公里(默认)
];
$range = $rangeMap[$level] ?? 100;
- 计算边界框:
$lngMin = $lng - $range / 111.32 / cos($lat * PI() / 180);
$lngMax = $lng + $range / 111.32 / cos($lat * PI() / 180);
$latMin = $lat - $range / 111.32;
$latMax = $lat + $range / 111.32;
性能对比:
| 数据量 | 优化前 | 优化后 | 提升 |
|---|---|---|---|
| 1万条 | 2.5s | 0.05s | 50x |
| 10万条 | 25s | 0.08s | 312x |
3. RPC微服务通信
平台支持gRPC协议,这是微服务通信的最佳选择。
为什么选择gRPC?
gRPC相比传统HTTP API有以下优势:
| 特性 | HTTP/REST | gRPC |
|---|---|---|
| 协议 | 文本(JSON) | 二进制(Protobuf) |
| 传输效率 | 低(数据大) | 高(数据小) |
| 序列化速度 | 慢 | 快(5-10倍) |
| 跨语言支持 | 需要手动适配 | 自动生成代码 |
| 流式传输 | 不支持 | 支持(单向流/双向流) |
| 代码量 | 手动解析 | 自动生成 |
关键优势:
- 任何语言对接:支持Go、Java、Python、Node.js、C#、PHP等20+种语言
- 协程友好:完美配合Swoole协程,无阻塞
- 内存运行:常驻内存,无需每次请求启动
- 性能更快:二进制协议,传输速度提升3-5倍
- 资源占用少:相比传统HTTP API,内存占用降低50%以上
服务间通过RPC调用,Swoft提供了优雅的注解方式:
定义Proto文件(traffic.proto):
syntax = "proto3";
package traffic;
service TrafficService {
rpc NearList(NearRequest) returns (NearResponse);
rpc CreateCarpooling(CarpoolingRequest) returns (CommonResponse);
}
message NearRequest {
float lng = 1;
float lat = 2;
int32 level = 3;
}
message NearResponse {
repeated Carpooling items = 1;
int32 total = 2;
}
PHP服务端实现:
/**
* @RpcService(name="trafficService", version="1.0")
*/
class TrafficService
{
/**
* 查询附近顺风车
*/
public function nearList(float $lng, float $lat, int $level = 3): array
{
return CarpoolingDao::nearList($lng, $lat, $level);
}
}
服务消费者通过@Reference注解注入:
/**
* @Reference(name="trafficService", version="1.0")
*/
private $trafficService;
public function near(Request $request): Response
{
$data = $this->trafficService->nearList(
$request->get('lng'),
$request->get('lat'),
$request->get('level', 3)
);
return context()->getResponse()->withData($data);
}
跨语言调用示例:
// Go客户端
conn, _ := grpc.Dial("localhost:8307", grpc.WithInsecure())
client := pb.NewTrafficServiceClient(conn)
req := &pb.NearRequest{
Lng: 102.83,
Lat: 24.88,
Level: 3,
}
resp, _ := client.NearList(context.Background(), req)
4. 支付系统集成
支付系统支持微信和支付宝,需要区分PC端和移动端:
public function createOrder(Request $request): Response
{
$deviceType = getDeviceType(); // H5/Pc
// 支付方式判断
$method = $this->getPaymentMethod($channel, $deviceType);
// 微信PC端: Native, 支付宝PC端: PcWeb, 移动端: H5
$order = [
'ser_name' => 'aigc',
'amount' => $amount * 100, // 转为分
'channel' => $channel, // Wechat/Alipay
'method' => $method,
'body' => '套餐名称',
'source' => '总部自营',
'user_id' => $userId ?: null,
'temp_id' => $tempId ?: null,
];
return $this->orderApi->create($order);
}
5. 自动化部署
为了提高开发效率,我实现了完整的自动化部署流程:
# 部署脚本
#!/bin/bash
git pull origin master
composer install --no-dev
php bin/swoft stop
php bin/swoft start -d
Git提交后自动触发部署,无需人工干预。
API文档管理
使用Swagger自动生成API文档,部署在:
-
生产环境:api.micro.lck.yn.cn/
接入模式与商业化思考
灵活的接入方式
平台提供两种接入模式,开发者可以根据项目发展阶段自由选择:
1. 共享API模式(适合项目初期)
适用场景:
- 项目刚起步,用户量和并发较低
- 希望节省服务器和运维成本
- 快速验证商业想法
优势:
- 零运维成本:无需搭建服务器、数据库等基础设施
- 快速上线:5分钟即可完成接入
- 按需授权:根据项目域名进行授权,灵活便捷
- 本地开发友好:localhost等本地域名默认已授权,开发无忧
授权方式:
- 通过申请域名授权,绑定项目前端域名
- 本地开发环境(localhost、127.0.0.1)默认已授权
- 域名审核通过后,即可在生产环境使用
2. 独立部署模式(适合项目成长期)
适用场景:
- 项目已有一定用户量和流量
- 需要更高的性能和稳定性
- 数据安全要求更高
优势:
- 完全独立:网关、微服务、数据库全部独立部署
- 跨服务器架构:可根据需要分布式部署
- 性能无上限:根据业务需求灵活扩展
- 数据完全掌控:所有数据存储在自有服务器
部署灵活性:
方式1:单机部署(小型项目)
┌──────────┐
│ 单服务器 │
└──────────┘
方式2:分布式部署(中型项目)
┌────┐┌────┐┌────┐
│网关││应用││数据库│
└────┘└────┘└────┘
方式3:集群部署(大型项目)
┌────┐┌────┐┌────┐
│网关││应用││数据库│
│集群││集群││集群 │
└────┘└────┘└────┘
无缝迁移路径
平台设计了平滑的迁移路径:
项目起步期 → 项目成长期 → 项目成熟期
共享API → 独立部署 → 完全私有化
(零成本) (逐步) (掌控)
迁移优势:
- 代码无需修改:API接口保持一致
- 数据平滑迁移:支持数据导出和导入
- 无缝切换:域名授权即可切换模式
技术支持
提供多渠道技术支持:
- 微信:kmwmkj
- 邮箱:admin@lck.yn.cn
- 电话:15687658489(微信同号)
公益与可持续
做公益不代表不能商业化,关键是找到平衡点:
公益初心:
- 始终记得为什么出发,不要因为商业化而偏离公益使命
- 为公益项目提供技术支持,降低公益项目的技术门槛
可持续发展:
- 公益也需要资金支持,合理的商业化能让平台走得更远
- 通过商业化项目反哺公益项目,形成良性循环
开放共赢:
- 欢迎更多公益项目接入,共同服务社会
- 建立开发者社区,共享技术资源和经验
经验总结
技术层面
- 协程编程思维:协程不是万能的,要避免阻塞操作,使用连接池、协程客户端等
- 服务拆分粒度:不要过度拆分,按业务领域划分,保持服务独立但不过于分散
- 数据库优化:善用MySQL 8.0的空间索引,地理位置查询性能提升显著
- 监控告警:建立完善的监控体系,及时发现和处理问题
产品层面
- 文档先行:好的API文档能让开发者快速上手,降低接入门槛
- 示例代码:提供Vue/React/小程序等多语言示例,覆盖主流技术栈
- 渐进式开放:先开放基础接口,逐步开放高级能力
- 社区运营:建立开发者社区,收集反馈,持续改进
商业层面
- 灵活接入:提供共享API和独立部署两种模式,满足不同阶段需求
- 公益初心:始终记得为什么出发,为公益项目降低技术门槛
- 可持续发展:合理的商业化能让平台更好地服务公益
- 开放共赢:欢迎更多项目接入,共同创造价值
展望
未来计划:
- 扩展服务:验证服务已支持邮箱验证(发送验证码、邮箱验证)和阿里云短信验证(代码已完成并测试通过),后续更换通过审核的短信模板ID即可正常使用
- 多区域部署:在更多地区部署节点,降低延迟
- AI能力开放:将AI算命等服务标准化后对外开放
- 社区建设:建立开发者社区,鼓励共享代码和经验
- 接入示例:提供更多接入示例(Vue、React、微信小程序等)
- 管理后台:开发可视化的域授权管理系统
接入指南
快速接入
- 联系授权:通过微信、邮箱或电话申请域名授权
- 获取密钥:获取项目的API密钥和配置信息
- 配置调用:根据文档配置API调用
- 测试上线:本地测试通过后即可上线
本地开发说明:
- localhost、127.0.0.1等本地域名默认已授权
- 开发过程中无需额外配置
技术支持
- 微信:kmwmkj
- 邮箱:admin@lck.yn.cn
- 电话:15687658489(微信同号)
- API文档:api.micro.lck.yn.cn/
结语
技术不仅是工具,更是一种改变世界的力量。作为一名开发者,我有幸能用自己的专长帮助他人,这让我感到无比充实。
我希望通过这个共享API平台,降低技术门槛,让更多人能够快速实现自己的想法。无论你是想做公益项目,还是想开发商业应用,都可以在这里找到你需要的基础能力。
如果你也想接入我的共享API平台,欢迎联系我。让我们一起用技术创造价值,让世界变得更美好一点。
联系方式:
- 微信:kmwmkj
- 邮箱:admin@lck.yn.cn
- 电话:15687658489(微信同号)
- 网关地址:api.micro.lck.yn.cn/
作者简介:李成坤(Ckli),后端工程师,系统架构师,技术总监。从事PHP开发近20年,现任云南某科技公司技术总监。热衷于公益事业,用技术帮助需要帮助的人。
个人主页:www.lck.yn.cn/ 技术博客:blog.lck.yn.cn/