Ckli的blog

[绝不人云亦云] 只发亲测、完整的教程

从零构建共享API平台:基于Swoft 2.0的微服务架构实践


<本文介绍如何基于Swoft 2.0框架>

<构建共享API网关平台,探讨公益与技术,商业化的平衡之道。>


## 前言


做公益这件事,我走了好多年。中间有过委屈,有过难,甚至看着自己搭建的平台,明明能帮人,却因"不会吆喝"而少有人问津时,也会陷入迷茫。但每当想起乡镇里,有人为了赶一趟班车,天不亮就守在路边;残障朋友想找份能做的活,却被大平台的门槛挡在门外;还有那些假期里,为买不到票、怕堵车而发愁的乡亲们,我又觉得这件事必须得做下去。


——摘自《七家坡的"摆渡人"》


作为一名在PHP领域深耕近20年的后端工程师,我一直在思考:如何用技术力量帮助更多人,同时又能让技术实现可持续发展?本文将分享我基于Swoft 2.0框架构建共享API平台的实践经验。


## 项目背景


我的共享API平台目前已经支撑了多个公益项目:


- **七家坡基层互助站** (https://lo.lck.yn.cn/)

  提共基于用户当前位置(查询、发布)拼车、运营(车辆、路线)信息等便民服务


- **AI合集** (https://ai.lck.yn.cn/)

  基于AI的(含八字算命,将持续增加更多服务)传统文化服务


这些项目虽然面向不同场景,但都需要相同的底层能力:用户认证、地理定位、支付、数据存储等。为了避免重复造轮子,我决定构建一个**共享API平台**,让所有项目都能快速接入这些通用能力。


## 技术选型:为什么选择Swoft 2.0?


在选型时,我对比了多个PHP框架:


| 框架 | 协程支持 | 微服务 | 学习成本 | 性能 |

|------|---------|--------|---------|------|

| Laravel | 无 | 无 | 低 | 中 |

| Hyperf | 有 | 有 | 中 | 高 |

| Swoft 2.0 | 有 | 有 | 中 | 高 |


最终选择**Swoft 2.0**的原因:


1. **成熟的协程支持**:基于Swoole扩展,提供原生协程能力,性能接近Go语言

2. **gRPC原生支持**:内置gRPC支持,可与任何语言无缝对接

3. **微服务架构**:内置RPC服务注册与发现,完美契合我的分布式架构需求

4. **注解驱动**:类似Spring Cloud的注解机制,代码简洁优雅

5. **完善的生态**:内置连接池、AOP、任务调度等企业级功能


### 关于框架选择的真实思考


**Swoft 2.0的现状**:

- 官方早已停止维护,官网已无法访问

- 基本查不到相关资料,社区支持很少

- 很多功能文档缺失,需要自己摸索


**为什么还是选择了它?**


1. **协程性能优势**:Swoole扩展的性能优势难以替代

2. **架构设计优秀**:微服务、RPC、注解机制的设计理念先进

3. **自主掌控**:既然官方不维护,我就自己维护


**填坑之路**:

- 很多功能的实现方案,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`):


```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自动刷新机制**:


```php

// 中间件中实现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`计算距离的方式效率低下:


```sql

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

```


**问题**:

- 每次查询都要计算全表距离,性能极差

- 无法使用索引,随着数据量增加性能急剧下降


#### 优化方案


采用**边界框预过滤 + 空间索引**的双重优化策略:


```sql

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

```


**优化要点**:


1. **添加空间索引**:


```sql

ALTER TABLE sys_carpooling

ADD COLUMN location POINT NOT NULL COMMENT '位置坐标' AFTER lat,

ADD SPATIAL INDEX idx_location (location);

```


2. **范围级别参数化**:


```php

$rangeMap = [

    1 => 10,   // 10公里

    2 => 50,   // 50公里

    3 => 100,  // 100公里(默认)

];


$range = $rangeMap[$level] ?? 100;

```


3. **计算边界框**:


```php

$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`):


```protobuf

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服务端实现**:


```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`注解注入**:


```php

/**

 * @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

// 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端和移动端:


```php

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. 自动化部署


为了提高开发效率,我实现了完整的自动化部署流程:


```bash

# 部署脚本

#!/bin/bash

git pull origin master

composer install --no-dev

php bin/swoft stop

php bin/swoft start -d

```


Git提交后自动触发部署,无需人工干预。


## API文档管理


使用Swagger自动生成API文档,部署在:


- **生产环境**:https://api.micro.lck.yn.cn/


- **测试环境**:https://apitest.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(微信同号)


### 公益与可持续


做公益不代表不能商业化,关键是找到平衡点:


**公益初心**:

- 始终记得为什么出发,不要因为商业化而偏离公益使命

- 为公益项目提供技术支持,降低公益项目的技术门槛


**可持续发展**:

- 公益也需要资金支持,合理的商业化能让平台走得更远

- 通过商业化项目反哺公益项目,形成良性循环


**开放共赢**:

- 欢迎更多公益项目接入,共同服务社会

- 建立开发者社区,共享技术资源和经验


## 经验总结


### 技术层面


1. **协程编程思维**:协程不是万能的,要避免阻塞操作,使用连接池、协程客户端等

2. **服务拆分粒度**:不要过度拆分,按业务领域划分,保持服务独立但不过于分散

3. **数据库优化**:善用MySQL 8.0的空间索引,地理位置查询性能提升显著

4. **监控告警**:建立完善的监控体系,及时发现和处理问题


### 产品层面


1. **文档先行**:好的API文档能让开发者快速上手,降低接入门槛

2. **示例代码**:提供Vue/React/小程序等多语言示例,覆盖主流技术栈

3. **渐进式开放**:先开放基础接口,逐步开放高级能力

4. **社区运营**:建立开发者社区,收集反馈,持续改进


### 商业层面


1. **灵活接入**:提供共享API和独立部署两种模式,满足不同阶段需求

2. **公益初心**:始终记得为什么出发,为公益项目降低技术门槛

3. **可持续发展**:合理的商业化能让平台更好地服务公益

4. **开放共赢**:欢迎更多项目接入,共同创造价值


## 展望


未来计划:


1. **扩展服务**:验证服务已支持邮箱验证(发送验证码、邮箱验证)和阿里云短信验证(代码已完成并测试通过),后续更换通过审核的短信模板ID即可正常使用

2. **多区域部署**:在更多地区部署节点,降低延迟

3. **AI能力开放**:将AI算命等服务标准化后对外开放

4. **社区建设**:建立开发者社区,鼓励共享代码和经验

5. **接入示例**:提供更多接入示例(Vue、React、微信小程序等)

6. **管理后台**:开发可视化的域授权管理系统


## 接入指南


### 快速接入


1. **联系授权**:通过微信、邮箱或电话申请域名授权

2. **获取密钥**:获取项目的API密钥和配置信息

3. **配置调用**:根据文档配置API调用

4. **测试上线**:本地测试通过后即可上线


**本地开发说明**:

- localhost、127.0.0.1等本地域名默认已授权

- 开发过程中无需额外配置


### 技术支持


- **微信**:kmwmkj

- **邮箱**:admin@lck.yn.cn

- **电话**:15687658489(微信同号)

- **API文档**:https://api.micro.lck.yn.cn/


## 结语


技术不仅是工具,更是一种改变世界的力量。作为一名开发者,我有幸能用自己的专长帮助他人,这让我感到无比充实。


我希望通过这个共享API平台,降低技术门槛,让更多人能够快速实现自己的想法。无论你是想做公益项目,还是想开发商业应用,都可以在这里找到你需要的基础能力。


如果你也想接入我的共享API平台,欢迎联系我。让我们一起用技术创造价值,让世界变得更美好一点。


**联系方式**:

- 微信:kmwmkj

- 邮箱:admin@lck.yn.cn

- 电话:15687658489(微信同号)

- 网关地址:https://api.micro.lck.yn.cn/


---


**作者简介**:李成坤(Ckli),后端工程师,系统架构师,技术总监。从事PHP开发近20年,现任云南某科技公司技术总监。热衷于公益事业,用技术帮助需要帮助的人。


个人主页:https://www.lck.yn.cn/

技术博客:https://blog.lck.yn.cn/


发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

«   2026年2月   »
1
2345678
9101112131415
16171819202122
232425262728
控制面板
您好,欢迎到访网站!
  查看权限
网站分类
搜索
最新留言
    文章归档
    网站收藏
    友情链接
    • RainbowSoft Studio Z-Blog
    • 订阅本站的 RSS 2.0 新闻聚合

    Powered By Z-BlogPHP 1.5.2 Zero

    Copyright Ckli Rights Reserved.