在前面的章节中,我们设置了代理,于是所有的 HTTP 请求都可以先到达本地开发服务器,再被转发。在实际的开发中,后端的服务不一定马上可用,这就需要本地服务器另外一个能力:模拟数据(mock)。设置代理是 mock 的前提。

一个 ajax 请求发送到本地开发服务器后,我们可以设置:如果请求满足某个规则,则不转发这个请求,而是直接返回一个「假」结果给浏览器。在实际的开发中,我们常常先和服务端的同学商定 http 请求的接口接受什么参数,返回什么结果,然后先用 mock 数据来模拟,自己和自己「联调」。等待服务端同学开发好了,再解除 mock,用真实数据「联调」。

模拟正常返回数据

设置模拟数据时需要在工程根目录下的 mock 子目录中的建立文件。首先在工程中增加 mock 目录,并在其中创建文件 puzzlecards.js(取其他名字也可以,名字这里不需要)。如果想 mock 掉我们在上一个章节中的向 /dev/random_joke 的 ajax 调用,需要写入以下内容到文件,

  1. const random_jokes = [
  2. {
  3. setup: 'What is the object oriented way to get wealthy ?',
  4. punchline: 'Inheritance',
  5. },
  6. {
  7. setup: 'To understand what recursion is...',
  8. punchline: "You must first understand what recursion is",
  9. },
  10. {
  11. setup: 'What do you call a factory that sells passable products?',
  12. punchline: 'A satisfactory',
  13. },
  14. ];
  15. let random_joke_call_count = 0;
  16. export default {
  17. 'get /dev/random_joke': function (req, res) {
  18. const responseObj = random_jokes[random_joke_call_count % random_jokes.length];
  19. random_joke_call_count += 1;
  20. setTimeout(() => {
  21. res.json(responseObj);
  22. }, 3000);
  23. },
  24. };

如果你不断地刷新页面,会发现每次拿到的数据是不同的。并且由于 setTimeout 的存在使得卡片的更新变慢了。

模拟服务端数据 - 图1

我们通过这个例子解释一下怎么写 mock 数据。

首先,整个文件需要 export 出一个 js 对象。对象的 key 是由

  1. <Http_verb> <Resource_uri>

构成的,值是 function,当一个 ajax 调用匹配了 key 后,与之对应的 function 就会被执行。函数中我们调用 res.json 就可以给浏览器返回结果。函数中可以使用 setTimeout 来模拟异步调用服务时的时延。

模拟出错

利用 res.status 也可以模拟 http 请求出错。例如,我们把文件中的 export default 块替换成下面的内容,

  1. export default {
  2. 'get /dev/random_joke': function (req, res) {
  3. res.status(500);
  4. res.json({});
  5. },
  6. };

在 dva model 中我们加入简单的错误捕获:

  1. import { message } from 'antd';
  2. // ... 原有逻辑不修改
  3. try { // 加入 try catch 捕获抛错
  4. const puzzle = yield call(request, endPointURI);
  5. yield put({ type: 'addNewCard', payload: puzzle });
  6. yield call(delay, 3000);
  7. const puzzle2 = yield call(request, endPointURI);
  8. yield put({ type: 'addNewCard', payload: puzzle2 });
  9. } catch (e) {
  10. message.error('数据获取失败'); // 打印错误信息
  11. }

于是可以看到出错状况下的页面:

模拟服务端数据 - 图2

在每一个调用点做打印错误信息很麻烦,这里只是为了展示 mock 出错场景。在实际的开发中,一般会统一处理 http 请求错误时的信息提示。

简单数据模拟

刚才的模拟中,mock 具备动态改变、延时返回等能力,如果你不需要这个能力,也可以简单地使用对象。

  1. export default {
  2. 'get /dev/random_joke': {
  3. setup: 'What is the object oriented way to get wealthy ?',
  4. punchline: 'Inheritance',
  5. },
  6. };