如何在开发过程中搭建简单的假数据服务器

在开发一块新功能的过程中,我们通常会涉及到与后端接口联调的问题。新的界面、新的后端接口,这时候在开发的时候往往前端就很尴尬,后端不依赖前端,但是前端十分依赖后端。

大部分应用都会有或多或少地依赖后端数据,有的界面只需要简单搞个假数据传入即可,但是我们还需要应对很多复杂情况,比如:

  • 处理无数据、返回错误、各类非正常的状态;
  • 处理分页数据的情况;
  • 模拟一个请求中、请求失败、请求结果返回的情景;

这时候如果能够写一个简单的服务器,你请求真实的接口url,只需要给手机设置一个代理,就返回你设置的假数据。这样你就可以完全抛开其他依赖的顾虑,可以像正常情况一样开发、校验结果,而不是依赖写死在代码里的各种假逻辑(这样做也会为后面的开发带来一些隐患)。

实际上服务器本身的逻辑是非常简单的,但是要真正得搭建成你所需要的环境,需要一些复杂功夫。本文以nodejs为例,具体描述一下如何在本机上搭建测试服务器。

使用node搭建起简单的服务器脚本

1. 安装

Unix 用户可以使用命令行安装nodejs。

Windows 用户可以直接下载安装包

安装成功后如果在命令行下输入node -v能够打印出版本信息,说明安装成功了。

2. 简单服务器

Node 服务器可以运行在“IP:PORT”上,我们可以通过如下代码来在127.0.0.1:2333端口上搭建起一个简单的服务器:

server.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const http = require('http');
http.createServer( (req, res) => {
// 返回码200,返回头中标识内容为json
res.writeHead(200, {'Content-Type': 'text/json'});
let resp = {
code : 0,
time : 1469981217,
data : {
name : 'desmond',
gender : 'male'
}
};
res.end(JSON.stringify(resp)); // 将resp转换为JSON字符串返回。
}).listen(2333, '127.0.0.1', )

之后输入node server.js,然后我们到浏览器中访问localhost:2333就可以看见:

image

具体的信息可以参考Nodejs-http.

3. IDE配置

从IDE环境切换到脚本环境来写代码总会不顺手,推荐一个我认为比较容易上手的配置吧:

  • 编辑器 Sublime Text 3,没啥好说的,好用。
  • 代码补全 TernJS, Tern-Sublime,是js下代码提示、补全的利器,极其推荐!
  • 错误检查 ESLint, SublimeLinter-ESLint 是一款js的静态检查、错误提示的利器,Sublime的插件也非常好用,配置很简单。

配上这三个,你就会觉得用起来已经蛮舒服了。

Nginx反向代理

nginx 搭建服务器的强大处之一就是它的代理能力,配置也十分简洁。

如果要模拟最终的请求的话,我们应该是原封不动的保留请求url: ‘www.desmond.com/api/something’。首先我们需要 在手机上设置代理,将ip配置到自己电脑上,端口配为80 。但是你的电脑识别到这个请求后,怎么让它导流到你的node服务器,这是一个问题。如果你代码写死的ip+端口来访问,未免有点太low了,我们既然折腾了这么多,那可以继续往下走一步:反向代理

反向代理,简而言之,就是一个分发请求的代理。前向代理 是直接发给目标服务器,但是它会做一些额外的处理工作。反向代理不一样,它自己相当于是一个服务器,请求到它手里,它根据请求去不同服务器上拉取数据。

1. 安装Nginx

Linux用户可以使用命令行:

1
2
apt-get update
apt-get install nginx

OSX用户可以用Homebrew:

1
brew install nginx

Windows用户可以下载安装包

2. 配置代理

我们希望针对’www.desmond.com/api/something’下的url交由node服务器(2333端口)处理,其他情况下继续发送,可以在nginx.conf里面这么配置(可以在命令行下输入nginx -t找到配置文件位置):

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
server {
listen 本机ip:80;
server_name www.desmond.com;
#charset koi8-r;
access_log /Users/desmond/Nginx/api.access.log;
error_log /Users/desmond/Nginx/api.error.log;
location / { //默认情况原路继续
resolver 8.8.8.8;
proxy_pass http://$http_host$request_uri;
proxy_set_header Host $http_host;
proxy_connect_timeout 5;
}
location /api { //检测到api路径下的,转发到端口2333
proxy_pass http://localhost:2333;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}

这里如果希望原路继续的那些url域名解析配合你的host(此处使用8.8.8.8来做DNS解析),你可以参考StackOverflow的一个提问

这样一来,你所有手机上访问的www.desmond.com/api/something就导到你的nodejs服务器上啦,尽情配置假数据来测试吧~~

4. 配合Charles使用

如果使用Charles的话,手机上一般配的代理是”ip:8888”,那么此时需要做一件事:本地的host设置本机ip www.desmond.com,这样才能保证 www.desmond.com域名下的请求被导流到nginx服务器,从而导流到自己的nodejs服务器上。

最终搭建

直接使用node,还是有一些繁琐的。既然我们的目的是“简单”,那么可以考虑一下使用express 。它封装了很多API,然呢使用起来非常方便。其中一项就是路由(Route)。它意思简单来说就是: www.desmond.com/api/a 由 a 的逻辑处理,www.desmond.com/api/b 由 b 的逻辑处理。

我相信一个新模块的服务器接口肯定不止一个,假如我们现在接口文档上写着:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
1. 提交个人信息:www.desmond.com/api/personal
方法:POST
返回示例:
{
code : 0,
time : 1469981217
}
2. 获取未来n天天气信息:www.desmond.com/api/weather
方法:GET
参数:day 未来天数
返回示例:
{
code : 0,
time : 1469981217,
data : {
items : [
date : '2016-08-02',
state : 'sunny'
],
//...
}
}

那么你可以使用来做一个简单的ROUTE+请求处理:

server.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 express = require('express');
const url = require('url');
let app = express();
app.post('/api/personal', function (req, res) { //针对/api/personal 的 post请求返回
res.writeHead(200, {'Content-Type': 'text/json;charset=utf-8'});
res.end(JSON.stringify({
code : 0,
time : 1469981217
}));
});
app.get('/api/weather', function (req, res) { //针对/api/weather 的 get请求返回
res.writeHead(200, {'Content-Type': 'text/json;charset=utf-8'});
let count = url.parse(req.url, true).query.day; //解析传入的day参数
if(count) { //若有,根据day参数生成item
let tmpList = [];
let tmpDate = new Date();
for(let i = 0; i < count; i++ ) {
tmpDate.setDate(tmpDate.getDate() + 1);
tmpList.push({
date : `${tmpDate.getFullYear()}-${tmpDate.getMonth() + 1}-${tmpDate.getDate()}`,
state : `sunny - ${i}`
});
}
res.end(JSON.stringify({
code : 0,
time : 1469981217,
items : tmpList
}));
} else { //若无,则返回错误信息
res.end(JSON.stringify({
code : -1,
msg: 'you must send param \"day\"',
time : 1469981217
}));
}
});
app.listen(2333, function(req, res) {
console.log(`You have run node host.`);
});

注意:不要忘记安装express,(npm install express –save)即可。

编辑结束后运行一下node server.js,你可以看到输出:

You have run node host.

这时我们可以尝试请求一下 localhost:2333,可以看到返回:

image

大功告成~~

如果希望node server一直在后台跑(使用node server.js时shell会卡在当前运行中),可以使用ForeverJS

更简单的办法

如果不想折腾太多,可以直接写一个json静态文件去返回:

data.json

1
2
3
4
{
"code" : 0,
"time" : 1469981217
}

*注意:手写json的话,里面的 key 必须以字符串形式(双冒号包围)存在。

server.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
const fs = require('fs');
const express = require('express');
let app = express();
app.get('/api/weather', function (req, res) { //针对/api/weather 的 get请求返回
res.writeHead(200, {'Content-Type': 'text/json;charset=utf-8'});
fs.readFile('data.json', 'utf8', (err, data) => { //读取data.json
if(err) { //错误时返回异常
res.end(JSON.stringify({
code : -1,
msg : 'Read File error!'
}));
return;
}
res.end(data);
});
});
app.listen(2333, function(req, res) {
console.log(`You have run node host.`);
});

这样就非常简单,不过缺点就是无法动态地处理。