react-native开发ReactNativeReact Native开发技巧

react中请求接口的封装

2018-01-24  本文已影响632人  sidney_c
1. 新建一个dva项目。使用antd 或者antd-mobile组件库。
$ npm install dva-cli -g
$ dva -v
$ dva new dva-quickstart
$ npm start
$  npm  install antd babel-plugin-import --save
或者是 
$  npm  install antd-mobile babel-plugin-import --save

导入方式css

{
  "entry": "src/index.js",
  "env": {
    "development": {
      "extraBabelPlugins": [
        "dva-hmr",
        "transform-runtime",
        ["import", { "libraryName": "antd-mobile", "style": "css" }]
      ]
    },
    "production": {
      "extraBabelPlugins": [
        "transform-runtime",
        ["import", { "libraryName": "antd-mobile", "style": "css" }]
      ]
    }
  }
}
2. 在该项目的src中utils 创建名为request文件夹。
$ cd  dva-quickstart
$ cd  src 
$ cd utils 

新建文件夹名为request,然后在request文件夹下面创建名为helpers的文件夹以及index.js 和 README.md , request.js 如图所示:

在helpers 下建三个js文件 combineURL.js , isAbsoluteURL.js , serialize.js


image.png

combineURL.js中 :


image.png

isAbsoluteURL.js中 :


image.png

serialize.js中 :


image.png
3. 在utils下创建一个与request同级的lang.js

lang.js 如下:

export const isPresent = (obj) => {
  return typeof obj !== 'undefined' && obj !== null;
};

export const isBlank = (obj) => {
  return typeof obj === 'undefined' || obj === null;
};

export const isBoolean = (obj) => {
  return typeof obj === 'boolean';
};

export const isNumber = (obj) => {
  return typeof obj === 'number';
};

export const isString = (obj) => {
  return typeof obj === 'string';
};

export const isArray = (obj) => {
  return Array.isArray(obj) || Object.prototype.toString.call(obj) === '[object Array]';
};

export const isDate = (obj) => {
  return obj instanceof Date && !isNaN(obj.valueOf());
};

export const isFunction = (obj) => {
  return typeof obj === 'function';
};

export const isJsObject = (obj) => {
  return obj !== null && (isFunction(obj) || typeof obj === 'object');
};

export const isPromise = (obj) => {
  return isPresent(obj) && isFunction(obj.then);
};

export const isEmpty = (obj) => {
  if (isBlank(obj)) {
    return true;
  }

  if (obj.length === 0) {
    return true;
  }

  for (const key in obj) {
    if (Object.prototype.hasOwnProperty.call(obj, key)) {
      return false;
    }
  }

  return true;
};

export const normalizeBlank = (obj) => {
  return isBlank(obj) ? null : obj;
};

export const normalizeBool = (obj) => {
  return isBlank(obj) ? false : obj;
};

export const stringify = (token) => {
  if (isString(token)) {
    return token;
  }

  if (isBlank(token)) {
    return String(token);
  }

  const ret = token.toString();
  const newLineIndex = ret.indexOf('\n');
  return (newLineIndex === -1) ? ret : ret.substring(0, newLineIndex);
};

export class PromiseWrapper {
  // Excutes promises one by one, e.g.
  // const promise = () => new Promise(...)
  // const promise2 = () => new Promise(...)
  // sequentialize([ promise, promise2 ])
  static sequentialize = promiseFactories => {
    let chain = Promise.resolve();
    promiseFactories.forEach(factory => {
      chain = chain.then(factory);
    });
    return chain;
  }

  // Promise finally util similar to Q.finally
  // e.g. finally(promise.then(...))
  /* eslint-disable consistent-return */
  static finally = (promise, cb) => promise.then(res => {
    const otherPromise = cb();
    if (typeof otherPromise.then === 'function') {
      return otherPromise.then(() => res);
    }
  }, reason => {
    const otherPromise = cb();
    if (typeof otherPromise.then === 'function') {
      return otherPromise.then(() => {
        throw reason;
      });
    }
    throw reason;
  })
}
/* eslint-enable consistent-return */

export class StringWrapper {
  static equals = (s1, s2) => s1 === s2;

  static contains = (s, substr) => s.indexOf(substr) !== -1;

  static compare = (a, b) => {
    if (a < b) {
      return -1;
    } else if (a > b) {
      return 1;
    }

    return 0;
  }
}

/* eslint-disable max-params */
export class DateWrapper {
  static create(
    year,
    month = 1,
    day = 1,
    hour = 0,
    minutes = 0,
    seconds = 0,
    milliseconds = 0
  ) {
    return new Date(year, month - 1, day, hour, minutes, seconds, milliseconds);
  }

  static fromISOString(str) {
    return new Date(str);
  }

  static fromMillis(ms) {
    return new Date(ms);
  }

  static toMillis(date) {
    return date.getTime();
  }

  static now() {
    return Date.now() || new Date();
  }

  static toJson(date) {
    return date.toJSON();
  }
}
/* eslint-enable max-params */

这个是dva自动生成的request.js 把这个文件换下名字requests.js,它与lang.js同级。


image.png
4. 打开在request文件下request.js,进行编辑:

request.js

import fetch from 'dva/fetch';
import { isEmpty } from '../lang';
import serialize from './helpers/serialize';
import combineURL from './helpers/combineURL';
import isAbsoluteURL from './helpers/isAbsoluteURL';
import { apiBaseUrl } from '../../config';
import { Toast } from 'antd-mobile';

const wait = ms => new Promise(resolve => setTimeout(resolve, ms));

const timeout = (p, ms = 30 * 1000) =>
  Promise.race([
    p,
    wait(ms).then(() => {
      const error = new Error(`Connection timed out after ${ms} ms`);
      error.statusCode = 408;
      throw error;
    }),
  ]);

// Request factory
function request(url, options, method) {
  const { endpoint, ...rest } = interceptRequest(url, options, method);
  const xhr = fetch(endpoint, rest).then(interceptResponse);
  return timeout(xhr, request.defaults.timeout).catch((error) => {
    // return Promise.reject(error);
    
  });
}

request.defaults = {
  baseURL: apiBaseUrl,
  timeout: 10 * 5000,
  headers: {
    Accept: 'application/json',
  },
};

// Headers factory
const createHeaders = () => {
  const headers = {
    ...request.defaults.headers,
  };

  // const auth = JSON.parse(localStorage.getItem('auth'+sessionStorage.getItem("hid")));
  
  // const token = sessionStorage.getItem('token'); // <Michael> 登录location获取到的token存放l
  
  
  // if (auth) {
  //   // Toast.info(`请稍等: ${token}`, 2);
  //   // Toast.loading('');
    
  //   headers.Authorization = auth.Token;
  // } else if (token) {
  //   // <Michael>;
  //   // Toast.info(`请稍等: ${token}`, 2);
  //   // Toast.loading('');
  //   headers.Authorization = token;
    
  // }
  headers.Authorization = "app";
  return headers;
};

// Request interceptor
function interceptRequest(url, options, method) {
  let endpoint;
  if (isAbsoluteURL(url)) {
    endpoint = url;
  } else {
    endpoint = combineURL(request.defaults.baseURL, url);
  }

  let data = {
    method,
    endpoint,
    headers: createHeaders(),
  };

  if (!isEmpty(options)) {
    data = {
      ...data,
      ...options,
    };

    if (options.json) {
      data.headers['Content-Type'] = 'application/json;charset=utf-8';
      data.body = JSON.stringify(options.json);
    }

    if (options.form) {
      data.headers['Content-Type'] = 'application/x-www-form-urlencoded;charset=utf-8';
      data.body = serialize(options.form);
    }

    if (options.body) {
      data.body = options.body;

      const auth = JSON.parse(localStorage.getItem('auth'+sessionStorage.getItem("hid")));

      if (auth) {
        if (auth && options.body instanceof FormData && !options.body.hasPatientid) {
          // options.body.append('patientid', auth.Patientid);
        }
      }
    }

    if (options.params) {
      endpoint += `?${serialize(options.params)}`;
      data.endpoint = endpoint;
    }
  }

  return data;
}

// Response interceptor
/* eslint-disable consistent-return */
function interceptResponse(response) {
  return new Promise((resolve, reject) => {
    const emptyCodes = [204, 205];

    // Don't attempt to parse 204 & 205
    if (emptyCodes.indexOf(response.status) !== -1) {
      return resolve(response.ok);
    }

    if (response.ok) {
      const contentType = response.headers.get('Content-Type');
      if (contentType.includes('application/json')) {
        resolve(response.json());
      }

      resolve(response);
    }

    if (response.status === 401) {
      // return Toast.fail('认证信息已过期,请重新登录', 2, () => {
      // return Toast.fail('请重新登录', 2, () => { 
        localStorage.removeItem('auth'+sessionStorage.getItem("hid"));
        // sessionStorage.removeItem('token');
        location.reload();
        // TODO:跳转登录路由
      // });
    }

    const error = new Error(response.statusText);
    try {
      response.clone().json().then((result) => {
        error.body = result;
        error.response = response;
        reject(error);
      });
    } catch (e) {
      error.response = response;
      reject(error);
    }
  });
}
/* eslint-enable consistent-return */

// suger
request.get = (url, options) => request(url, options, 'GET');

request.head = (url, options) => request(url, options, 'HEAD');

request.options = (url, options) => request(url, options, 'OPTIONS');

request.post = (url, options) => request(url, options, 'POST');

request.put = (url, options) => request(url, options, 'PUT');

request.delete = (url, options) => request(url, options, 'DELETE');

request.del = request.delete;

export default request;

5. 这样你就可以在今后的项目正常使用按照以下步骤
module.exports = {
    apiBaseUrl: "http://172.118.100.50/api/",
};

之后再services文件下就可以这样去下啦:

import request from '../utils/request/request';

export function queryScaleMenu(start, limit) {
   const body = new FormData();
    body.append('start',start);
    body.append('limit', limit);
    return request.post('news/menu/query', { body });
} 
上一篇下一篇

猜你喜欢

热点阅读