内网部署可综合管理并利于测试的工具——Yapi

在使用上,官方文档已经很清晰了,文档

文章主要功夫是写一下安装环节遇到的问题,主要是项目年久失修,而各路环境又是突飞猛进的进行改变,所以造成其有兼容性问题。

容器环境

docker部署yapi是极其方便易用的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# 账号:admin@docker.yapi
# 密码:adm1n
version: '3'
services:
yapi-web:
image: jayfong/yapi:1.10.2
container_name: yapi-web
ports:
- 40001:3000
environment:
- YAPI_ADMIN_ACCOUNT=admin@docker.yapi
- YAPI_ADMIN_PASSWORD=adm1n
- YAPI_CLOSE_REGISTER=true
- YAPI_DB_SERVERNAME=yapi-mongo
- YAPI_DB_PORT=27017
- YAPI_DB_DATABASE=yapi
- YAPI_MAIL_ENABLE=false
- YAPI_LDAP_LOGIN_ENABLE=false
- YAPI_PLUGINS=[{"name":"interface-oauth2-token","name":"add-user"}]
depends_on:
- yapi-mongo
links:
- yapi-mongo
restart: unless-stopped
yapi-mongo:
image: mongo:4.4.4
container_name: yapi-mongo
volumes:
- ./data/db:/data/db
expose:
- 27017
restart: unless-stopped

但这里面会碰到一个问题,在使用mock测试集的时候会碰到safeify引发的Error: EROFS: read-only file system问题,跟着#2376修改完成之后,使用assert依然会碰到Error: Method Promise.prototype.then called on incompatible receiver [object Object]

该问题也被记录在#2536

解决方法当时未找到,这里就没有深究了。

本地部署

环境要求:

Node.js(7.6+)

MongoDB(2.6+)

当前node版本太高,Yapi需要一个低版本的node

参考:怎么在Ubuntu中更新node的版本,安装工具n。使用工具n,指定版本安装,我这里安装的是12.16.3。

1
sudo n 12.16.3

参考官方安装文档

1
2
3
4
5
6
7
8
9
10
mkdir yapi
cd yapi
git clone https://github.com/YMFE/yapi.git vendors //或者下载 zip 包解压到 vendors 目录(clone 整个仓库大概 140+ M,可以通过 `git clone --depth=1 https://github.com/YMFE/yapi.git vendors` 命令减少,大概 10+ M)

cp vendors/config_example.json ./config.json //复制完成后请修改相关配置

cd vendors
npm install --production --registry https://registry.npm.taobao.org
npm run install-server //安装程序会初始化数据库索引和管理员账号,管理员账号名可在 config.json 配置
node server/app.js //启动服务器后,请访问 127.0.0.1:{config.json配置的端口},初次运行会有个编译的过程,请耐心等候

config.json中设置MongoDB的用户,需要MongoDB开启auth

注意,config.json的引用是在文件server/yapi.js中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
docker pull mongo:latest
docker run -itd --name mongo -p 27017:27017 mongo --auth

docker exec -it mongo mongo admin

//进入admin。如果没有admin库,会自动创建admin库
user admin

//创建一个新账号 权限root
db.createUser({user:"test1",pwd:"test1",roles:["root"]})
//创建一个新账号 用户名test1 密码test1 权限dbOwner 只能访问yapi数据库
db.createUser({user:"test1",pwd:"test1",roles:[{role:'dbOwner',db:'yapi'}]})

//账号授权:用户名 密码。 回车,返回1,认证成功。
db.auth("test1","test1")

config.json中DB的设置:

1
2
3
4
5
6
7
8
"db": {                                                                                                                                               
"servername": "127.0.0.1",
"DATABASE": "yapi",
"port": 27017,
"user": "test1",
"pass": "test1",
"authSource": "" // 若是为空验证失败,则填入admin试试
}

所有新建完成后,mock会遇到新问题。

UnhandledPromiseRejectionWarning: TypeError: Converting circular structure to JSON

需要改动,vendors/server/utils/sandbox.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
const Safeify = require('safeify').default;

module.exports = async function sandboxFn(context, script) {
// 创建 safeify 实例
const safeVm = new Safeify({
timeout: 3000,
asyncTimeout: 60000,

// 修复断言错误
unrestricted: true,
unsafe: {
modules: {
assert: 'assert'
}
}

});
safeVm.preset('const assert= require("assert");')

// 解决 https://github.com/YMFE/yapi/issues/2543, https://github.com/YMFE/yapi/issues/2357
script += `; return {
Function: this.Function,
eval: this.eval,
header: this.header,
query: this.query,
body: this.body,
mockJson: this.mockJson,
params: this.params,
resHeader: this.resHeader,
httpCode: this.httpCode,
delay: this.delay,
Random: this.Random,
cookie: this.cookie
}`;
// 执行动态代码
const result = await safeVm.run(script, context)

// 释放资源
safeVm.destroy()
return result
}

开启LDAP

开启之后即可接通公司的账户体系。

1
2
3
4
5
6
7
8
9
10
11
"ldapLogin": {                                                                                                                                           
"enable": true,
"server": "ldap://xxxxxx:389",
"baseDn": "xxxx.xx", // 账户体系中的用户名
"bindPassword": "xxxxx",
"searchDn": "DC=xxxx,DC=xxxx",
"searchStandard": "&(objectClass=user)(sAMAccountName=%s)",
"emailPostfix": "@xxxxxx.com",
"emailKey": "userPrincipalName",
"usernameKey": "cn"
}