在开发基于api交互、前后端分离的网页应用时,经常会遇到几个问题:
- 前端页面已经编排好了,但是后台接口还没准备好,或者是突然出现Bug,这样没办法进行对接测试。
- 我们希望服务器返回特定类型的数据,以测试某页面在特定条件下是否存在问题,但作为前端我们一般不会接触到后端代码和数据库,每次都找后端添加模拟数据又很麻烦。
为解决这两个问题,最简单的解决办法就是搭建一个mock server,专门返回需要的模拟数据。
webpack-dev-server
是我们开发vue、react时必备的工具,通过webpack-dev-server
的before
钩子,可以在webpack-dev-server
上添加我们需要的mock server功能,而不需要另行搭建服务器。
在一通搜索后,我找到了这篇文章和这个webpack中间件webpack-api-mocker,只需要少许修改就能webpack-dev-server
当做mock server来用,并且对同一URL下的GET
、POST
、PATCH
等不同的HTTP METHOD
做分别处理,支持热切换。
使用方法很简单,在webpack.dev.conf.js
的devServer
中添加新钩子before
,将所有请求交由apiMocker
处理,然后当需要使用模拟数据时,只需要将请求的URL改为webpack服务器上既可。
npm install webpack-api-mocker --save-dev
复制代码
const apiMocker = require('webpack-api-mocker')
config = {
...
devServer: {
before(app) {
apiMocker(app, path.resolve('mock/api.js'))
}
}
...
}
复制代码
api.js
const fs = require('fs');
function fromJSONFile(filename) {
return (req, res) => {
const data = fs.readFileSync(`mock/data/${filename}.json`).toString();
const json = JSON.parse(data);
return res.json(json);
};
}
const proxy = {
'GET /app/user/profile': fromJSONFile('profile'),
};
module.exports = proxy;
复制代码
修改URL
axios.get('user/info').then(...)
// 修改URL,加上前缀
axios.get('http://127.0.0.1:8080/' + 'user/info').then(...)
复制代码
更进一步
经过上面的步骤,mock server已经基本能运行了,但还是有一些不友好。每次需要使用模拟数据时,都要修改项目源码,改写请求的URL,在测试完毕后还得再改回来,如果该请求在源码内有多处地方使用,那改动的地方就多了,比较麻烦。我们可以再进行一些改进。
改进的思路就是开启mock server后,将所有对api服务器的请求都发送到webpack server
上,webpack server
拦截并处理所有已定义有模拟数据的接口请求,而未定义的接口请求则转发到api服务器上。
上面说的那个项目作者已经合并了我的PR,下面这段可以不用理了,继续用上面那个webpack-api-mocker
首先,我们要对前面用到的那个中间件webpack-api-mocker进行改进,修改后的代码在我的github上,插件主要就一个文件
index.js
,复制下来直接使用即可。修改了那些内容可以看commit log
然后添加一个新的npm命令dev-mock
,定义一个环境变量MOCK
来控制是否开启mock server
:
"script": {
"dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
+ "dev-mock": "MOCK=true webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
}
复制代码
webpack config中当MOCK
变量存在时才开启mock server
config = {
...
devServer: {
if (process.env.MOCK) {
before(app) {
apiMocker(app, path.resolve('mock/api.js'), {
proxy: {
'/app//*': 'http://api.leaderlegend.com',
}
});
}
}
}
...
}
复制代码
为了在代码中使用环境变量MOCK
,我们要在webpack config内传递该值。如何传值参考StackOverflow上的这个回答Passing environment-dependent variables in webpack 。
config = {
...
devServer: ...
plugins: [
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: process.env.NODE_ENV,
MOCK: process.env.MOCK,
}
}),
...
]
...
}
复制代码
通过判断环境变量MOCK
来确定api服务器地址,这里最好保持第一个path相同以更方便转发
const BASE_URL = process.env.MOCK ? 'http://127.0.0.1:8080/app/' : 'http://api.harlanluo.com/app/';
复制代码
到此为止已经全部完成,需要使用模拟数据时,使用npm run dev-mock
命令来运行,,不需要时则使用npm run dev
,无需对项目源码对做任何修改。