docs: function getRequestValues(request, mockRequestConfig) {
      var querystring = mockRequestConfig ? mockRequestConfig.querystring : {};
      var header = mockRequestConfig ? mockRequestConfig.header : {};
      var body = mockRequestConfig ? mockRequestConfig.body : {};
  
      // 先找出所有的必选参数, 最后一起做验证
      var requestValues = {
          querystring: {},
          header: {},
          body: {}
      };
  
      // 验证请求接口时是否包含特定的 querystring 参数
      if (querystring) {
          for (var expectedName in querystring) {
              // 只验证必传参数
              if (isRequired(expectedName)) {
                  // 去除用作必要参数的标识
                  var _expectedName = stripRequiredPlaceholder(expectedName);
                  var expectedValue = querystring[expectedName];
                  var factValue = request.query[_expectedName];
  
                  requestValues.querystring[_expectedName] = {
                      expectedValue: expectedValue,
                      factValue: factValue
                  };
              }
          }
      }
  
      // 验证请求接口时是否包含特定的 header
      if (header) {
          for (var expectedName in header) {
              if (isRequired(expectedName)) {
                  var _expectedName = stripRequiredPlaceholder(expectedName);
                  var expectedValue = header[expectedName];
                  var factValue = request.get(_expectedName);
  
                  requestValues.header[_expectedName] = {
                      expectedValue: expectedValue,
                      factValue: factValue ? decodeURIComponent(factValue) : factValue
                  };
              }
          }
      }
  
      // 验证请求接口时是否包含特定的 body 数据
      if (body) {
          // request's "Content-Type" HTTP header field matches the MIME type
          // http://expressjs.com/en/4x/api.html#req.is
          if (request.is('application/x-www-form-urlencoded')) {
              // XXX nodejs 自带的 querystring 无法解析嵌套的对象
              // 例如: querystring 是 a%5Bb%5D%3D1, 解析出来为 {'a[b]': 1}
              // 但是我们想要的是 {a:{b:1}}
              var urlencoded = qs.parse(request._rawBody);
  
              for (var expectedName in body) {
                  if (isRequired(expectedName)) {
                      var _expectedName = stripRequiredPlaceholder(expectedName);
                      var expectedValue = body[expectedName];
                      var factValue = urlencoded[_expectedName];
  
                      requestValues.body[_expectedName] = {
                          expectedValue: expectedValue,
                          factValue: factValue
                      };
                  }
              }
          } else if (request.is('multipart/form-data')) {
              // multipart/form-data 一般用得比较少, 简单的使用正则表达式来解析
              var multipartRegExp = /Content-Disposition:\s*form-data;\s*name\s*=\s*"(\S+)"\s+(\S+)/mg;
  
              var multipartFormData = {};
              var result = null;
              while ((result = multipartRegExp.exec(request._rawBody)) != null) {
                  // 从表单数据中匹配出字段名和字段值
                  var fieldName = result[1];
                  var fieldValue = result[2];
                  multipartFormData[fieldName] = fieldValue;
              }
  
              for (var expectedName in body) {
                  if (isRequired(expectedName)) {
                      var _expectedName = stripRequiredPlaceholder(expectedName);
                      var expectedValue = body[expectedName];
                      var factValue = multipartFormData[_expectedName];
  
                      requestValues.body[_expectedName] = {
                          expectedValue: expectedValue,
                          factValue: factValue
                      };
                  }
              }
          } else if (request.is('json')) {
              var factValue = null;
              try {
                  factValue = JSON.parse(decodeURIComponent(request._rawBody));
              } catch (e) {
                  factValue = request._rawBody;
                  console.warn('body json parse error', e);
              }
  
              // 在 body 中放置 raw 数据时, 不是 key-value 键值对形式的数据
              // 因此使用 Content-Type MIME 作为 key 来标记
              // 但是不验证里面具体的数据类型, 只验证其是否是 object 类型
              requestValues.body[request.get('Content-Type')] = {
                  expectedValue: body,
                  factValue: factValue
              };
          } else {
              // 针对其他的 MIME 类似数据不做验证, 都认为他们是字符串
              // 希望扩展的人可以扩展验证规则
              if (!util.isEmptyObject(body)) {
                  requestValues.body[request.get('Content-Type')] = {
                      expectedValue: body.toString(),
                      _expectedValue: body,
                      factValue: request._rawBody + ' ' // 不管你有没有传 body, 都伪造了一个非空的值
                  };
              }
          }
      }
  
      return requestValues;
  }