YAPI这名字用过的人都知道,是国内接口管理工具里少有的既轻量又功能完整的方案。去年年中有个新项目,前后端分离,接口量大,团队又分散在好几个城市,靠文档表格和在线协作文档根本顶不住。当时选型对比了市面上几个开源工具,最后还是定了YAPI,原因无非三点:一是部署轻,一个Node服务加一个MongoDB就能跑;二是它的接口调试、Mock、自动化测试能力够用;三是源码开放,遇到不满足的地方可以自己改,这正是二次开发的价值所在。
这篇文章不打算只讲"安装完能跑起来"这种入门级内容。我的目标是把从零开始部署,到理解源码结构,到实际做二次开发改动,再到覆盖式升级维护这一整条链路讲清楚。重点放在那些官方文档没写、但实际操作中几乎必然遇到的坑。适合谁看?准备在团队内部搭建接口管理平台的技术负责人,或者接了类似的"安装+定制"任务、需要自己折腾一遍的开发工程师。基础的Linux和Node知识假设你有,纯粹的界面操作不多说。
1. 动手安装之前:先搞清楚二次开发需要什么
很多人装YAPI上来就抄一段Docker命令,跑通了才开始想"我要改什么东西",结果发现容器里的文件和宿主隔离,改起来特别别扭。我的建议是先想明白二次开发的范围,再决定用哪种安装方式。
1.1 源码安装和容器安装怎么选
YAPI的部署方式大体分三类:官方提供的可视化安装、Docker容器、源码手动部署。如果只是临时试用,官方脚本或Docker最省事。但只要动了二次开发的念头——比如改前端Logo、加一个内部登录接口、调整自动化测试的逻辑——就必须走源码手动部署这条路,原因很实际:容器相当于一个封闭盒子,你改宿主上的文件它不一定进得去,就算用volume挂载,YAPI的前端是构建产物,改完还得重新编译,在容器里做这些事很绕。
我做这次部署时一开始也图省事,用Docker跑了一个测试环境,后面要改前端样式的时候后悔了,重新回滚到源码部署重来了一遍。所以如果你想二次开发,或者未来大概率会做定制,直接源码部署是唯一理性的选择。
部署前最好先盘一下团队的能力。YAPI前端基于React,后端是Node.js的Express框架,数据库用MongoDB。团队有没有会Node的人、有没有人写过React,这决定了后续能改到什么程度。还有一个核心问题:你们的接口数据流和团队权限体系是什么样的,这直接影响你是否要改后端权限模块。把这些想清楚再动手,比装完再返工强太多。
1.2 版本搭配与基础环境要求
我第一次部署时在版本上踩了坑,这里直接给出一组实测稳定的组合:
| 组件 | 版本 | 说明 |
|---|---|---|
| Node.js | 12.x 或 14.x LTS | 后续编译前端时兼容性最好 |
| MongoDB | 4.x | 3.x 也没问题,但建议4.x |
| Redis | 不需要 | YAPI默认不用Redis |
| 操作系统 | CentOS 7 / Ubuntu 20.04 | Linux环境最稳 |
| 构建工具 | npm 6.x | 与Node 12/14匹配 |
Node版本这里要特别强调。有一个很隐蔽的坑:YAPI的源码拉下来后,npm install时某些依赖在Node 17以上会报编译错误,主要是node-gyp相关的原生模块。这个报错很迷惑,"ERR! gyp ERR!"刷一大屏,我刚开始以为是网络问题。后来把Node从16降到14,装的时候一路顺利。
MongoDB如果选4.x,要注意服务器的Linux发行版能不能装对应源。CentOS 7默认源里只有3.6,需要手动添加MongoDB官方源。装完后设置开机自启很关键,服务器的防火墙要放开27017端口(内网环境的话建议不要对外暴露)。
2. 从源码拉取到YAPI跑起来的完整过程
我以CentOS 7环境为例,把实际操作步骤展开写一遍。这一步的意义不只是"跑起来",更是为了后面二次开发建立可控的环境,所以要特别注意每个操作的实际作用,而不是机械地敲命令。
2.1 获取源码并准备配置
YAPI的源码托管在GitHub上,仓库名称记住两个关键词就行:YMFE和yapi。我通常是直接clone主干代码,因为很多修复和功能更新都在master上。clone下来之后,会看到根目录下有一个package.json和api/子目录,真正的后端代码在api这个目录里。
# 拉取源码 git clone https://github.com/YMFE/yapi.git cd yapi # 安装依赖 # 注意:在根目录和api目录下都需要执行一次 npm install --registry=https://registry.npmmirror.com cd api && npm install --registry=https://registry.npmmirror.comnpm install如果网速慢或失败,换个镜像源能省去大量时间。国内环境用npmmirror这个镜像一般没问题。
接下来是配置文件。YAPI支持两种方式:一种是通过可视化页面在浏览器里配置数据库和账号;另一种是直接在config.json里写好配置。二次开发场景下推荐用配置文件方式,因为可以版本化,团队拿到后直接改配置就能复现环境。
在api/目录下创建config.json,内容样例:
{ "port": "3000", "adminAccount": "admin@example.com", "timeout": 120000, "db": { "connectString": "mongodb://127.0.0.1:27017/yapi", "servername": "127.0.0.1", "DATABASE": "yapi", "port": 27017 }, "mail": { "enable": true, "host": "smtp.example.com", "port": 465, "from": "no-reply@example.com", "auth": { "user": "no-reply@example.com", "pass": "your-password" } } }adminAccount就是你登录后的管理员账号,推荐配一个真实邮箱,因为YAPI的部分通知功能会用到邮件。如果你在纯内网环境,mail部分直接设enable为false,不影响核心使用。
2.2 启动时需要紧盯的校验点
配置写好后,在api/目录下执行:
node server/app.js第一次启动会做两件事:初始化数据库索引,创建管理员账号。日志里看到"web"和"server"两个服务都起来了,就说明启动基本成功。
需要注意,YAPI会启动两个服务进程,一个是API服务,一个是静态资源服务。默认都在3000端口。启动日志中如果出现"MongoError: connect ETIMEDOUT"之类的报错,多半是MongoDB没起来或者连接串写错。
浏览器访问http://服务器IP:3000,如果看到登录页面就说明前端资源也正常。用config.json里adminAccount配的邮箱登录,初始密码是yapi.admin,登录后建议立即修改密码。
提示:如果你是二次开发之后再来启动,建议第一次初始化完成后先不要急着登录操作。先把数据库备份一份干净的初始状态,后面改坏了可以随时恢复。这个习惯能救你很多次。
2.3 项目初始化与成员管理的直观认知
登录进去后,先把"项目"这个概念理解清楚。YAPI里的组织架构是:分组可以理解成目录,项目挂在分组下;项目里的内容主要是接口分类,分类下是具体接口。多人协作时,先建一个测试分组,把一个项目分配给指定成员。这块不在二次开发范围内,但部署完必须做,因为它会影响你对权限数据结构的理解,而权限模型恰恰是二次开发时绕不开的东西。
以管理员身份创建一个分组,再在分组里创建项目,然后把团队成员加进来,分配不同角色。至此基础环境就算完全跑通了。接下来才是重头戏:看源码,改想要的功能。
3. 前端目录结构与常见改造切入点
YAPI的前端代码是React技术栈,跟一般的React项目一样,有清晰的目录划分。二次开发大多数需求都集中在前端,比如换Logo、调整页面文案、隐藏菜单、改造布局。这部分不涉及后端接口,最快也最容易出效果。
3.1 前端资源放在哪里
源码根目录下的static/目录就是前端资源所在。里面结构大概是这样的:
static/ /src React源码目录 /node_modules 依赖包目录 /build 编译后的静态文件目录默认访问时,YAPI用的是不带src的静态目录,也就是编译后的build产物。如果你改了src里的代码,不重新编译,页面不会生效。这导致很多人刚开始改完发现没变化,以为没改对。实际上必须执行前端构建命令:
cd static npm install npm run build执行完,build目录下的文件更新,重启服务,修改才会出现。构建过程比较慢,内存小的服务器可能执行到一半报错,这时候增加swap分区是一个有效的办法。
3.2 三个最常见的二次开发小改造
改造一:换掉Logo和站点标题
这个需求几乎每个公司在内部部署时都会有。YAPI的界面顶部有一个默认Logo和默认的"YAPI接口管理平台"标题,要改成自己的品牌。Logo文件通常放在static/src/yapi/Logo目录下,直接替换同名文件即可。标题则在static/src/目录下找到包含siteName或title字样的配置文件修改。改完重新构建。
改造二:隐藏某些入口菜单
比如有些公司希望隐藏"数据导出"功能,或者不想让普通成员看到"自动化测试配置"入口。前端菜单配置通常集中在static/src/的导航文件里,找到包含菜单项数组的代码,注释掉或删除对应项。我改过一次,发现菜单list里每一项是对象,直接注释掉要隐藏的那一项,构建完就生效。
改造三:对接公司内部登录体系
这个需求比较复杂,先说思路。YAPI前端在请求后端时带有一个token机制,登录成功后后端返回token,前端存在localStorage里。如果要对接自己的单点登录,就是在登录页面做跳转或调内部登录接口,登录成功后再调用一次后端登录接口获取token。听起来复杂,但实际改的仅仅是登录跳转逻辑和新增一个登录接口,后续后端二次开发的部分我会再说。
| 需求 | 前端改动点 | 是否涉及后端 | 工作成本 |
|---|---|---|---|
| 换Logo、改标题 | Logo文件、站点配置 | 否 | 小 |
| 菜单隐藏/权限控制 | 导航配置 | 轻微 | 小 |
| 对接统一登录 | 登录页、token管理 | 需要 | 较大 |
| 自定义接口请求头 | 请求封装文件 | 需要 | 中 |
前端二次开发有个容易被忽略的细节:cookie的跨域和sameSite策略。如果YAPI部署在一个域名下,你的前端请求跨域到后端时,浏览器的sameSite策略会拦截cookie。YAPI本身不重度依赖cookie,但部分登录场景会用到。遇到登录状态丢失、持续重定向的问题时,第一个先查这个。
4. 后端扩展:接口鉴权、自动化交底与脚本安全性
相比于前端的"看得见摸得着",后端二次开发是真正决定YAPI能否贴合团队流程的关键。做这一层开发之前,必须先花时间读一遍后端代码结构,否则就是在迷宫里乱撞。
4.1 后端启动流程与代码目录功能速览
YAPI后端主入口在api/server/app.js,Express的配置和路由挂载都在里面。开发时经常要动的是以下几个目录:
api/server/ /controllers 接口的具体逻辑 /middlewares 中间件:身份校验、请求日志等 /models 数据模型:MongoDB集合的结构定义 /routes 路由定义:URL路径与controller的映射 /utils 工具函数 /cron 定时任务
初次读这个项目时,建议从routes目录入手,因为你最先想改的接口通常都能在routes里找到映射关系。比如登录相关的逻辑在controllers/下的user.js里。了解了路由映射,也就明白了一个请求从前端发起、经过路由、命中controller的完整链路。
4.2 实战一:新增一个内部鉴权接口
当时我的团队有一个具体的需求:YAPI要对接公司内部的统一权限服务,实现"只要内部系统登录过,打开YAPI就自动登录"。实现思路是:在前端加一个"使用内部账号快速登录"的按钮,点击后请求一个自定义后端接口。这个接口接收内部系统传来的token,验证通过后直接生成YAPI的有效token并返回。
新增一个自定义接口,需要两步:
第一步,在routes/下新增一个文件,例如custom.js:
const { login } = require('../controllers/user.js'); const { verifyToken } = require('../utils/xxx.js'); // 自定义的token校验工具 module.exports = function(router) { router.post('/custom/login', async function(req, res) { try { const token = req.body.token; const userInfo = await verifyToken(token); if (!userInfo) { return res.json({ errcode: 403, errmsg: '内部鉴权失败' }); } const result = await login(userInfo.email, userInfo.password); res.json(result); } catch (e) { res.json({ errcode: 500, errmsg: e.message }); } }); };第二步,在app.js中挂载这个路由文件。通常app.js里有类似这样的一段路由挂载逻辑:
const customRouter = require('./routes/custom.js'); customRouter(router);这里有个经验:YAPI内部登录controller返回的result包含token字段,前端拿到后直接存入localStorage,之后所有请求都会自动带token。这个登录流程等于绕过了YAPI的密码校验,只做了内部系统的token验证。
4.3 实战二:自动化测试引擎的扩展思路
YAPI自带的自动化测试支持在接口用例中编写断言脚本,这部分脚本在前端运行。默认的断言能力有限,我做过一次扩展,主要替团队实现了"对上游接口的结果做二次校验后,再传给依赖它的接口"。核心思路是:在自动化测试的执行器文件中,找到一个skip和过滤器之类的扩展点,在接口执行前注入自定义逻辑。以YAPI的底层实现来看,它有自定义断言脚本入口,通常允许在before和after钩子里调用自定义函数。
实际改动不复杂,只要理解了YAPI测试脚本的执行顺序——请求前、请求后、断言——自定义逻辑就能插进去。我通常是直接把这些逻辑写在测试用例对应的脚本里,而不是动框架源码。这个做法的好处是:后续YAPI版本升级,不用再改框架层代码。
4.4 公共脚本的安全隐患——最容易翻车的点
这个必须单独拿出来说。YAPI的接口测试脚本可以保存公共脚本,一般在"自动化测试-公共脚本"里维护。由于这些脚本执行时能够调用Node的全局对象,如果没有安全限制,恶意脚本可以访问服务器的文件系统。这在跨部门多人使用的大团队里尤其危险。如果你负责YAPI的部署维护,必须检查是否有人创建了包含fs或child_process的公共脚本。我给过自己团队一个硬性规定:公共脚本只允许对响应数据进行截取和断言,严禁访问系统级对象。同时建议在服务端点做一层请求过滤或安全凭证管理,防止未授权用户利用脚本获取敏感信息。
5. 从开发到线上:覆盖式升级与日常维护经验
二次开发完成后,面临的下一个问题是:如何把改动后的YAPI稳定地跑在线上,并持续升级。很多时候开发环境跑得好好的,一上生产就各种问题。这里分享一下我惯用的升级流程和数据备份策略。
5.1 覆盖式升级:旧配置如何安全保留
YAPI源码升级时,最怕的是配置文件被覆盖。官方源码在更新过程中不会动你创建的config.json,但如果你改了源码目录下的公共文件,更新时就有冲突风险。我的处理方式是把整个api/下的config.json单独备份一份,升级流程如下:
# 备份配置 cp -r yapi/api/config.json /data/backup/ # 拉取新代码 cd /data/yapi git pull origin master # 重新安装依赖 npm install --registry=https://registry.npmmirror.com cd api && npm install --registry=https://registry.npmmirror.com # 覆盖式替换自定义的路由和自定义controller(具体文件看你的改动) cp /data/backup/custom.js api/server/routes/ # 重新构建前端 cd static && npm run build # 重启服务 pm2 restart yapi这里有个技术点:YAPI官方没有明确的"数据库迁移工具"概念,MongoDB的数据结构在升级时通常不用手动迁移。但如果跨大版本升级(比如从1.x到新版本),数据库结构变化后有可能会出现某些字段缺失。遇到这种情况,在备份后先起一个临时实例,连接旧数据库测试一下,确认没报错再切流量。这个步骤不要省,我就吃过一次亏——跨版本升级后,原来是字符串的字段变成了数组格式,老数据查询直接报错。
5.2 数据备份与快速恢复的实际操作
YAPI的数据全部在MongoDB里,备份就是对MongoDB做dump。我的备份策略是每天凌晨3点做一次全量备份,保留最近7天。备份命令:
mongodump --host 127.0.0.1 --port 27017 --db yapi --out /data/backup/yapi_$(date +"%Y%m%d")恢复时执行:
mongorestore --host 127.0.0.1 --port 27017 --db yapi /data/backup/yapi_20240101/yapi这里有个micro-tip:mongorestore恢复的db名称默认取备份目录的db名,如果原库名不叫yapi,你可能要把目录名改一下,或者用--nsInclude指定命名空间。我一般在备份脚本里就把命名空间写死,避免恢复时搞错。
验证备份不能等到出事才想起。我每个月会实际做一次恢复演练,起一个临时Mongo实例,然后执行mongorestore,再启动YAPI连接这个临时库,确认登录、项目、接口数据都在。这个"预演"能在真正故障时省下大量抢救时间,谁做谁知道。
5.3 pm2守护进程与开机自启
管理YAPI进程,我不建议直接nohup挂后台,而是用pm2做进程守护。配置很简单:
pm2 start process.jsonprocess.json的关键内容:
{ "apps": [{ "name": "yapi", "script": "api/server/app.js", "cwd": "/data/yapi", "instances": 1, "watch": false, "max_memory_restart": "1G", "env": { "NODE_ENV": "production" } }] }这里注意:instances务必设为1。YAPI内置了两个进程相互配合,如果你用pm2开多个实例,反而会引起端口冲突或数据不一致。watch建议关闭,避免源码变更后自动重启导致服务中断。
开机自启用pm2自带能力:
pm2 startup pm2 save这样服务器重启后YAPI会自动拉起,省去人为介入。
6. 那些安装和二次开发后的真实体验感悟
这次YAPI部署加定制改造,我走完了从需求梳理、环境选型、源码阅读、前后端改造到最终上线维护的完整闭环。如果让我再从头做一次,有一件事一定会提前做:先把"要改什么"列成清单,逐一标出需要动到前端还是后端,再决定代码改造的优先级。这样能避免来回切环境、反复构建前端框架的时间浪费。
有两点想特意强调。
第一,YAPI前端构建非常吃机器内存,如果你的服务器只有2G内存,构建时极容易卡死。要么增加swap空间,要么把构建放到本地开发机完成后,把build目录产物直接上传到服务器。这个做法也能作为团队协作标准:开发机负责构建,服务器只跑可用产物。
第二,依赖版本锁定非常关键。YAPI的依赖包虽然有package.json,但部分依赖没有锁版本。两周后重新npm install可能装出不同版本,导致某些功能异常。建议把package-lock.json纳入版本管理,明确作为还原依赖的唯一依据。这能避免"在我机器上没问题,服务器上就出错"的尴尬。
二次开发的边界也要心里有数。YAPI的核心架构到今天已经比较稳定,但前端框架和内部模块的组织方式并不算现代。如果需要做深度定制,尽量把自定义逻辑模块化、独立化——要么新增路由文件,要么以公共脚本的形式扩展,不要直接修改它的核心业务文件。尽量通过"外挂"而非"改造"的思路去解决问题,能让后续升级省力太多。
最后提醒一句:团队里一定要提前约定YAPI的管理规范,比如谁来维护公共脚本、谁有管理员权限、接口数据变更时如何同步。平台工具通常是越用越乱,趁早立规矩比以后费力清理更划算。