☰
Leancloud停服之后:BaaS平台迁移实战与替代方案选型指南
2026/10/3 23:17:44 网站建设 项目流程

1. Leancloud 到底是什么,为什么会被叫作“平价可爱”

1.1 初学者的第一个“云后端”

说实话,看到 Leancloud 停服公告的那一刻,我心里一半是早有预感,一半是确实难受。对一个从大学时代就用它写课程设计、写毕设、写各种练手 Demo 的人来说,它不只是个后端服务,更像是我编程路上的第一张“免费工位”。如果你没用过,我先用一句话说清楚:Leancloud 是国内最早一批做 BaaS(Backend as a Service,后端即服务)的云服务平台,你不需要买服务器、不需要配 Nginx、不需要手动管理数据库,注册一个账号,前端代码里引一行 SDK,就能立刻拥有一个带用户系统、数据存储和推送通知的后端。

当年它还叫 AVOS Cloud 的时候,我是在一篇“用云服务做一个 App 后台”的教程里认识它的。说实话那篇教程写得一般,但“不用买服务器就能做 App 后端”这句话对一个穷学生来说太有吸引力了。后来它改名成 Leancloud,中文文档越写越顺手,社区里的例子也越来越多,课程设计、社团活动报名、毕业设计,我身边一半同学的练手项目都是它撑起来的。

对当时的我们来说,它就像那个“平价又可爱”的选项:便宜到几乎没有门槛,界面配色清爽,文档里好多地方都带示例代码,连报错信息都比别的平台温柔一点。用现在的话说,它就是开发者工具里的“入门友好型产品”。

1.2 那套免费额度,是真的在替开发者着想

我记得当时的开发版是免费的,每天有请求次数和存储空间限制,但你正常做个课程设计、写个小工具、跑一个几百人的活动报名,完全够用。它没有像一些平台那样搞“新用户注册领多少额度、过期清零”,而是给了长期稳定的免费档位,这一点就非常良心。

更重要的是,Leancloud 把“后端”这个概念拆成了一个个看得懂的模块。你不需要一开始就理解负载均衡、反向代理、数据库连接池,只需要知道:我有一个表,里面存数据;我有一个函数,可以被前端调用。这种思维上的降级,恰好踩中了新手最需要的那一步——先建立“我能写出完整应用”的正反馈,再去补底层原理。

免费额度背后其实有一套很精巧的考虑:BaaS 的边际成本主要来自存储、流量和计算资源,个人开发者用量低,成本可控;等这批人毕业进了公司、或者自己的产品跑起来,自然会成为付费客户。这个算盘本身没问题,只是后来一些事情让这条路走不下去了,后面我会专门说。

2. 从功能拆解看它为什么能留住人

2.1 数据存储:把“数据库”装进口袋

Leancloud 的核心是它的数据存储服务,官方叫 mStorage。你不需要写建表 SQL,不需要维护数据库,直接在控制台创建 Class(可以理解成一张表),然后用 SDK 往里写 JSON 对象就够了。举个我当时最常写的例子:

const AV = require('leancloud-storage'); AV.init({ appId: '你的AppId', appKey: '你的AppKey' }); // 定义一个“消息”类 const Message = AV.Object.extend('Message'); const message = new Message(); message.set('content', '大家好,这是我的后端'); message.set('author', '张三'); message.set('likes', 0); await message.save();

存进去之后,查询也是 SDK 内置的,不用拼 SQL:

const query = new AV.Query('Message'); query.equalTo('author', '张三'); query.descending('createdAt'); const list = await query.find(); list.forEach(item => console.log(item.get('content')));

那时候的我觉得这简直像变魔术。后来才明白,它其实就是把 NoSQL 的存储模型包装成了“对象”,让你像操作本地变量一样操作云端数据。这种设计的价值不在于多高级,而在于第一次让你摸到了“前后端联调”的真实手感:数据存得进去、查得出来,接口调得通,一个完整的链路就在眼前。

但也要承认,这个便利是有代价的。由于不需要设计表结构,很多初学者(包括我)会把数据存得乱七八糟,字段命名随意、嵌套层级很乱、该关联的数据没有用 Pointer 关联。到迁移的时候,这些“欠债”都变成了要还的账。

2.2 云引擎:前端同学也能碰后端

除了数据存储,Leancloud 的云引擎也是一绝。它提供了一个 Node.js 运行环境,你可以直接在上面写云函数,前端通过 SDK 调用。举个例子:

AV.Cloud.define('getUserInfo', async (request) => { const userId = request.params.userId; const user = await new AV.Query('_User').get(userId); return { nickname: user.get('nickname'), avatar: user.get('avatar') }; });

前端调用就是一行:

const result = await AV.Cloud.run('getUserInfo', { userId: 'xxx' });

对一个以写前端为主的人来说,这相当于第一次亲手碰“后端逻辑”,又不用理解服务器部署、不用学 Linux。更重要的是,云引擎还能挂定时任务,比如每天凌晨统计一次日活、每周清理一次过期数据。我当时花了一个下午搞定了一个“每日签到统计”的定时任务,成就感是实实在在的。

现在回头看,云引擎在技术上不复杂,但它做对了一件事:把“后端开发”的门槛从“需要了解整个运维体系”降到了“会写一个函数”。这个思路后来被所有 Serverless 产品复制了,所以 Leancloud 其实算得上是中国 Serverless 概念的早期布道者之一。

2.3 用户系统、推送、短信这些“小零件”的大意义

Leancloud 还自带一堆开箱即用的小模块,单看每一个都不起眼,组合起来却是一个完整 App 后端的“最小闭环”。

用户系统是我用得最多的。AV.User 帮我把注册、登录、会话管理全封装好了:

const user = new AV.User(); user.setUsername('test'); user.setPassword('123456'); await user.signUp(); // 之后每次操作,SDK 会带上 sessionToken

那时候我完全不知道 session、cookie、Token 这些概念,但代码居然能跑通。后来做项目遇到需要自己写登录的时候,才回头补这些知识。这也是 Leancloud 这类平台的共同特点:让你先“用起来”,再用到某个深度后自然会去想“它是怎么实现的”。

推送、短信验证码、实时数据订阅也都是类似逻辑。比如发送短信验证码,一条 SDK 方法就搞定了,不用去对接运营商的接口。很多刚入门的人以为这些功能“很难”,其实只是没接触过——而 Leancloud 的价值,就是把这些“以为很难”的东西变得伸手就能够到。

3. 它为什么会走到停服这一步

3.1 免费策略与商业化的矛盾

先说一个最直白的现实:BaaS 本质上是一门“资源生意”,存储、带宽、计算都是真金白银的成本,而它的用户群又恰恰是对价格最敏感的人群。个人开发者习惯了免费额度,很难转化为付费用户;真愿意付费的企业用户,要求又多:私有化部署、定制功能、SLA 保障、合规审计,每一项都是成本。

这就让独立 BaaS 平台陷入了一个两难:对个人收钱,会把好不容易攒起来的口碑打掉;对企业放弃,又撑不起营收规模。说白了,就像开了一家平价食堂,学生顾客越来越多,但菜价不能涨、租金一直在涨,你还得另外开小灶去伺候能付得起钱的企业客户——两头都不容易讨好。

我之前和一些做开发者工具的团队聊过,他们的共同感受是:做开发者服务的“品牌好感度”很容易积累,但“盈利能力”非常难验证。尤其是当用户习惯了“免费 + 好用”,你一旦把某些功能放到付费墙后面,舆论压力会立刻涌上来。Leancloud 这么多年能保持免费档位不死,已经算很克制了。

3.2 大厂云生态的挤压

第二个原因是行业格局变了。最近几年,各个云服务大厂纷纷把“云函数 + 云数据库 + 对象存储 + 短信服务”打包成产品线,新用户注册还送一堆长期或短期额度。对普通开发者来说,在大厂一套体系里能搞定的事,没有理由拆到好几个平台去做;对一个公司来说,也更倾向于把云资源统一在一个供应商下,方便开票、审核和运维。

在这种挤压下,独立 BaaS 的差异化壁垒几乎消失。过去大家选 Leancloud,是因为它“小而美、中文文档好、专门做后端服务”;但当大厂用生态优势把同类功能做到近乎免费时,“小而美”就变成了“小而贵”或“小而难以维持”。开发者是实际的使用者,离开的时候虽然说一声“可惜”,但身体很诚实。

还有一个容易被忽略的变量:开源社区。Supabase、Parse Server 这类开源项目让“自托管一个 BaaS”变成了可能,开发者发现自己也可以拥有一套可控的、不会停服的平替。当“用别人的服务”和“用自己部署的服务”之间的差距越来越小,独立云服务平台的生存空间就被两头夹住了。

3.3 停服公告之后的普遍难题

停服这件事,最难的不是“不能再用了”,而是“存量用户怎么办”。我身边受影响的人大致分三类:

  • 做着玩的小项目:直接弃坑,数据导出来留个纪念,产品下线。
  • 正经在运营的小产品:必须在窗口期内完成数据迁移、域名切换、推送重配,相当折腾。
  • 还处于学习阶段的新手:突然发现教程里的平台没了,学习的路径被打断。

对第二类人来说,停服通知里通常会给一个明确的时间节点,要求你在那之前把数据导走。真正的问题是:很多人的产品已经上线很久,数据格式、代码逻辑、第三方配置全都深度绑定了平台提供的特性,迁移不是“复制粘贴”能搞定的。这也是所有“平台依赖症”的最终代价——你享受了多少便利,就得在告别时付出多少对应的心力。

从行业影响来看,这次停服更像一个信号:纯独立 BaaS 的商业模式已经越来越难走,未来开发者能依赖的“省心后端”,要么来自大厂的生态,要么来自自己掌握全套数据的开源方案,中间层的空间会越来越窄。

4. 停服前我做的迁移实操记录

4.1 第一步:把数据完整倒出来

停服公告出来后,我第一时间做的事不是唉声叹气,而是把所有数据从控制台和 API 两头分别导了一份。这里有个建议:不要把“第一次导出”当作“唯一一次导出”,先做一轮完整备份,再边改代码边增量导出,最后停服前再做一次兜底,三重保障。

我写了一个 Node.js 脚本,用官方 SDK 按 Class 逐个导出。关键的注意点是:如果没有特殊要求,尽量把时间戳、ACL、Pointer 关系这些“元信息”一起带出来。下面是我当时的做法,你参考着改就行:

const AV = require('leancloud-storage'); const fs = require('fs'); AV.init({ appId: process.env.APP_ID, appKey: process.env.APP_KEY }); async function exportClass(className) { const items = []; let lastCreatedAt = new Date(0); // 按 createdAt 增量翻页 const pageSize = 500; while (true) { const query = new AV.Query(className); query.greaterThan('createdAt', lastCreatedAt); query.ascending('createdAt'); query.limit(pageSize); const list = await query.find(); if (list.length === 0) break; items.push(...list.map((obj) => obj.toJSON())); console.log(`${className}: 已导出 ${items.length} 条`); lastCreatedAt = list[list.length - 1].get('createdAt'); if (list.length < pageSize) break; } fs.writeFileSync(`${className}.json`, JSON.stringify(items, null, 2)); } exportClass('Message').catch(console.error);

这里用greaterThan('createdAt', lastCreatedAt)而不是skip分页,是因为停服前夕很多人都在写数据,skip分页容易漏数据、也容易重复,按时间游标翻页更稳。导出完成后,我先把每个 Class 的总条数记下来,后面增量导出的时候可以对得出有没有缺漏。

4.2 第二步:选迁移目标

数据拿到手之后,就要考虑迁到哪去了。我自己当时对比了几个方向,这张表你可以直接收藏:

方案代表适合谁门槛备注
大厂 Serverless 全家桶云函数 + 云数据库 + 对象存储想在自家云生态里省事中等免费额度后按量付费
开源 BaaS 自托管Supabase、Parse Server想掌控数据、愿意学点运维偏高一台小服务器就能跑
传统后端重写Node/Python + MySQL/PostgreSQL本来就要做大的重构较高最可控,成本最高

我的选择是 Supabase:它本身是 Postgres,支持 SQL 和 REST 两种查询方式,自带用户系统和存储,还允许部署在自己的服务器上——就算再遇到类似情况,也不至于手忙脚乱。更重要的是,SQL 是通用标准,以后想换到任何一家云数据库都容易。

4.3 第三步:改造代码,保数据

迁移不只是“把 JSON 文件搬到新库”,中间要做几件具体的事:

第一,数据模型转换。Leancloud 的 Class 和 JSON 结构对应到 Postgres 就是表,需要把嵌套对象拆开,或者用 JSONB 类型存住一时拆不开的字段。我当时的原则是:能拆成列的就拆成列,拆不动就用 JSONB,尽量保留原始 JSON 作为兜底字段,万一后面发现丢了什么东西还能捞回来。

第二,类型还原。Leancloud 导出的 JSON 里,日期、指针、地理坐标都有特殊标记,比如日期会变成{ "__type": "Date", "iso": "2022-01-01T00:00:00.000Z" }。导入新库前要写一个转换脚本,把这些标记还原成新库对应的 datetime、外键、经纬度类型,这一步最容易悄悄丢数据。

第三,用户系统替换。Leancloud 的AV.User和新平台的用户体系不是一套,老用户的密码也没法直接迁移,常见做法是让老用户走一次“重置密码”流程,或者用邮箱/手机号作为唯一标识重建用户。我当时选了重置密码方案,产品和用户都能接受。

第四,云函数与定时任务重写。所有AV.Cloud.define的代码都要移植到新平台的函数服务或者自己的服务里,定时任务重新创建一个不复杂,但时间表达式要仔细核对一遍。

第五,推送和短信重新配置。新平台需要重新申请推送通道、配置签名和证书,短信模板也要在服务商后台重新审核。这些事项很碎,建议建一张事项清单逐项打勾。

5. 迁移过程中那些坑与排查实录

5.1 导出文件打开乱码、格式不标准

第一个坑是导出的文件根本不是标准 JSON 数组,而是“一行一个 JSON 对象”的 NDJSON 格式。用编辑器直接打开,如果对象里有特殊字符,很可能显示乱码或者卡死。解决办法是别用编辑器硬扛,写个小脚本逐行解析:

const fs = require('fs'); const lines = fs.readFileSync('Message.json', 'utf8').split('\n').filter(Boolean); const rows = lines.map((line) => JSON.parse(line)); console.log(rows.length);

如果文件特别大,建议用jq这类命令行工具先抽样检查几条,再决定要不要全量处理。我吃过一次亏:一根筋把一个大文件直接加载进内存,笔记本风扇狂转十分钟,最后进程崩了,白跑一趟。

5.2 日期、指针、Geo 点的类型还原

第二个坑就是上面提到的类型标记。数据导出来是一回事,导入新库是另一回事。如果你的数据里有Pointer,说明 Class 之间存在关联关系,导入顺序要先解析出所有外键的指向关系,才能保证导入后数据之间没有断链。我的踩坑经验是:

  • 日期类型:先转换成 ISO 字符串,再由目标数据库解析成时间类型。
  • 指针类型:记录好className+objectId的映射,导入主表后再回填外键。
  • 地理位置:保留经度纬度两个字段即可,新库的 PostGIS 或普通point类型都能处理。

这个环节是最容易“数据不报错但语义错误”的地方,比如时间全都变成null、外键全断掉,表面上看着导完了,实际上一查询就露馅。所以我强烈建议:导入完成后,用原来的数据量做一轮总行数核对,再抽样几条记录逐字段人工对比。

5.3 文件域名与推送配置过期

第三个坑是文件存储。Leancloud 的文件会有一个专属域名,停服后这个域名大概率也会失效。如果你早期把文件 URL 直接存进了数据表(而不是存文件 ID 再拼接 URL),迁移的时候就要花大力气替换所有 URL 前缀;更稳妥的做法是先把文件全部下载到本地或对象存储,再在数据里换成新地址。这个操作听着简单,真做起来会非常耗时,尤其图片多的时候。

推送和短信的配置也要重新弄。尤其是推送,不同的应用商店要求的厂商通道配置不同,新平台注册之后要重新绑定证书和密钥,光这一步我就对着一堆配置文件折腾了大半天。这类工作不涉及什么高深技术,但非常琐碎,唯一有效的办法就是把所有步骤写进清单,逐项确认,别信自己的记忆。

6. 告别之外:小白怎么选“下一个后端”

6.1 大厂云开发与 Serverless 阵营

如果你现在是一个新手,想找 Leancloud 的替代品,我会先按你的目标来分。如果你的目标是让一个 App 或小程序快速跑起来、不想碰运维,那么大厂云开发会是比较顺手的选项。它把数据库、存储、云函数和登录能力集成在一起,很多能力甚至比当年的 Leancloud 更丰富,免费额度也够初学者折腾。

要注意的是,这类服务本质上是“生态绑定”。你选择了它的数据库、登录和函数运行时,就意味着以后迁移的门槛也不会低。这和当年选择 Leancloud 并没有本质区别,只是把“停服风险”换成了“生态转换成本”。

6.2 开源 BaaS 阵营

如果你想从根上解决“平台停服”这件事,我会推荐开源 BaaS。Supabase 和 Parse Server 是比较成熟的两个选择,前者基于 Postgres,上手之后能顺便把 SQL 学好;后者几乎是 Parse 和 Leancloud 风格的后继者,结构上很接近,迁移思路也能复用。你只需要一台最便宜的云服务器,用 Docker 把服务跑起来,数据就真正在你手里了。

对应的代价是运维:系统更新、磁盘备份、宕机恢复,都要自己负责。但换个角度想,这也是值得的学费——学会这些,你的能力边界就超过了“会用某个平台”的程度。我身边很多同事后来复盘,都觉得这种“被逼着学运维”的经历反而是成长最快的一段。

6.3 我的三点选型建议

无论选哪条路,我有三点建议想送给正在看这段的你:

第一,给你的代码加一层“屏蔽层”。不要把 SDK 的调用散落在业务代码里,哪怕只是简单包一层dataService、pushService,在迁移的时候也能省下海量工作量。

第二,从第一天起就写备份脚本。不用很复杂,定时把数据库导出到本地或对象存储就够了。你永远不知道平台什么时候会通知你“下个月停服”。

第三,优先选“数据能导出成通用格式”的平台。JSON、SQL、CSV 都行,只要数据能出来,迁移就有出路。最怕的是平台把数据锁死在自家私有格式里,那才是真正的走投无路。

我在这次迁移里最深的体会是:工具会换,平台会停,但你真正学到的东西不会丢。当年在 Leancloud 上学会的前后端联调、数据建模、定时任务,换一个平台照样能用;反而是当年偷懒没学的那部分——比如备份、迁移、底层原理——这次被现实狠狠补了一课。如果你现在也用着某个云服务,哪怕它再“平价钱可爱”,也请记得定期把数据握在自己手里。这也是我写这篇记录的原因:纪念一个老朋友,也提醒后来的自己。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询