react中请求接口的封装

作者: sidney_c | 来源:发表于2018-01-24 18:49 被阅读632次
    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 });
    } 
    

    相关文章

      网友评论

      • 3c51465b71e4:4. 打开在helpers文件下request.js //应该是request下的request.js吧
        sidney_c:这是笔误 谢谢提醒

      本文标题:react中请求接口的封装

      本文链接:https://www.haomeiwen.com/subject/uobuaxtx.html