# Mock服务

Mock 数据是前端开发过程中必不可少的一环，是分离前后端开发的关键链路。通过预先跟服务器端约定好的接口，模拟请求数据甚至逻辑，能够让前端开发独立自主，不会被服务端的开发所阻塞。

在 Octopus-Pro 中，我们通过Webpack DevServer中自带的express服务，可能你以前看出来了，这种方式不同于一些拦截XHR或者做通过本地数据替换的形式，而是真实的创建了一个服务。

得益于此，用这种形式去mock数据，对代码的侵入性极小，你甚至只需要修改devServer的转发目标即可（如果你需要直接请求也是可以的，因为我们内置了对跨域CORS的处理）

不过我们还是建议你在源代码的本地（local）环境下使用devServer的proxy转发接口，这样的好处是不管后么怎么操作，源代码部分都不需要再进行修改，还能一并解决掉跨域问题

## 使用Mock功能
Octopus-pro约定了项目根目录下为mock文件夹下的文件为mock文件，index.js中规定了所有的Mock配置  

```javascript
// CORS库，用于跨域配置
const cors = require('cors')
// 解析请求体
const bodyParser = require('body-parser')
// 命令行着色
// const chalk = require('chalk')
// 模块，如果存在多个，请依次引入
const products = require('./controllers/test')

/**
params { app } express 主体
*/
function mock (app) {
  // 中间件调用
  app.use(cors())
  app.use(bodyParser.urlencoded({ extended: false }))
  app.use(bodyParser.json())
  // 这里可以配置路由匹配规则
  app.use('/mock/api/*', (req, res) => {
    /* 
    // console.log('请求路径:', req.baseUrl)
    // console.log('请求方法:', req.method)
    // console.log('请求query:', req.query)
    // console.log('请求体:', req.body)
    // console.log('请求Content-Type:', req.get('Content-Type'))
    // console.log('授权信息:', req.get('Authorization')) 
    */ 
    if (products[req.baseUrl]) {
      let resData = products[req.baseUrl]
      if (resData[req.method.toUpperCase()]) {
        resData = resData[req.method]
      }
      if (typeof resData === 'function') {
        resData = resData(req)
      }
      // 这里可以修改接口返回的基本数据结构
      res.json({
        code: 0,
        data: resData,
        message: '',
        timestamp: Date.now()
      })
    } else {
      res.status(404)
      res.end()
    }
  })

  // 如果需要模拟跨域请求,则放开以下注释，在另一端口监听服务
  // const port = 3000
  // app.listen(port, () => {
  //   console.log(chalk.green(`\nMock service is running at port ${port}`))
  // })
}
module.exports = mock
```
以上是一些mock服务的基础配置，你可以根据你的项目做适当的修改

## 配置Mock规则
以下我们以一个模块为例，讲解下如何配置mock规则,其中模块中的每个键都代表一条规则
```javascript
module.exports = {
  '/mock/api/cpu': () => {
    return {
      100: 1,
      50: 2
    }
  },
  '/mock/api/phone': {
    'GET': {
      info: '这是一个手机,请求类型get'
    },
    'POST': {
      info: '这是一个手机，请求类型post'
    }
  },
  '/mock/api/brand': {
    'GET': function (req, res) {
      // console.log('query参数：', req.query)
      // console.log('body参数：', req.query)
      if (req.query.brand === 'xiaomi') {
        return {
          info: '这是一个国产品牌'
        }
      } else if (req.query.brand === 'apple') {
        return {
          info: '这是一个美国品牌'
        }
      } else {
        return {
          info: '这是一个未知品牌'
        }
      }
    }
  }
}
```
:::tip 提示
所有的接口规则都以node module的形式导出，导出后会整合到一个对象下面，如果出现重复的话，将有可能被覆盖，所以这里的键（这里的键实际上就是最终要访问的Path）需要注意不能重复
:::

当客户端发起请求时，比如：'/mock/api/phone | GET'，那么本地的mock-server将会将其匹配到，对应的配置，并返回相应的数据，比如这条规则：
```javascript
'/mock/api/phone': {
    'GET': {
       info: '这是一个手机,请求类型get'
     }
}
```
这里的【键】,会匹配到访问接口的path,如果接口需要按Methods区分的话， 需要增加子属性来返回，如：GET | POST，如果不需要区分则可直接指向返回结果，返回结果最终会放置到data下面，这里最终的返回结果可以是具体的值、数组、Object,也可以是一个函数，如果是一个函数的话，则会取函数的返回值作为接口的返回，上面的接口的请求过程如下：   
请求信息
![](../.vuepress/public/img/req.png)

响应信息
![](../.vuepress/public/img/res.png)
