react中请求接口的封装

简介: 1. 新建一个dva项目。使用antd 或者antd-mobile组件库。$ npm install dva-cli -g$ dva -v$ dva new dva-quickstart$ npm start$ npm install ...
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 });
} 
目录
相关文章
|
3月前
|
前端开发 JavaScript 网络架构
react对antd中Select组件二次封装
本文介绍了如何在React中对Ant Design(antd)的Select组件进行二次封装,包括创建MSelect组件、定义默认属性、渲染Select组件,并展示了如何使用Less进行样式定义和如何在项目中使用封装后的Select组件。
114 2
react对antd中Select组件二次封装
|
3月前
|
前端开发 JavaScript UED
react或者vue更改用户所属组,将页面所有数据进行替换(解决问题思路)____一个按钮使得页面所有接口重新请求
在React或Vue中,若需在更改用户所属组后更新页面所有数据但不刷新整个页面,可以通过改变路由出口的key值来实现。在用户切换组成功后,更新key值,这会触发React或Vue重新渲染路由出口下的所有组件,从而请求新的数据。这种方法避免了使用`window.location.reload()`导致的页面闪烁,提供了更流畅的用户体验。
59 1
react或者vue更改用户所属组,将页面所有数据进行替换(解决问题思路)____一个按钮使得页面所有接口重新请求
|
3月前
|
前端开发
React添加路径别名alias、接受props默认值、并二次封装antd中Modal组件与使用
本文介绍了在React项目中如何添加路径别名alias以简化模块引入路径,设置组件props的默认值,以及如何二次封装Ant Design的Modal组件。文章还提供了具体的代码示例,包括配置Webpack的alias、设置defaultProps以及封装Modal组件的步骤和方法。
85 1
React添加路径别名alias、接受props默认值、并二次封装antd中Modal组件与使用
|
2月前
|
前端开发
react 封装防抖
react 封装防抖
34 4
|
3月前
|
前端开发
React技术栈-react使用的Ajax请求库实战案例
这篇文章介绍了在React应用中使用Axios和Fetch库进行Ajax请求的实战案例,展示了如何通过这些库发送GET和POST请求,并处理响应和错误。
61 10
React技术栈-react使用的Ajax请求库实战案例
|
3月前
|
前端开发
React技术栈-react使用的Ajax请求库用户搜索案例
这篇文章展示了一个React技术栈中使用Ajax请求库(如axios)进行用户搜索的实战案例,包括React组件的结构、状态管理以及如何通过Ajax请求获取并展示GitHub用户数据。
36 7
React技术栈-react使用的Ajax请求库用户搜索案例
|
6月前
|
存储 缓存 前端开发
react怎么只让接口请求一次
react怎么只让接口请求一次
103 0
|
3月前
|
前端开发
React页面跳转取消上一个页面的所有请求
React页面跳转时取消上一个页面的所有axios请求,通过axios拦截器设置cancelToken,并在页面跳转时调用cancel函数取消未完成的请求。
47 2
|
3月前
|
前端开发 JavaScript
React配合axios请求拦截校验session,403跳转至登陆页面
React中使用axios进行请求拦截,通过自定义事件监听和响应拦截实现403状态码时的自动登录页面跳转。
103 2
|
3月前
封装react-antd-table组件参数以及方法如rowSelection、pageNum、pageSize、分页方法等等
文章介绍了如何封装React-Antd的Table组件,包括参数和方法,如行选择(rowSelection)、页码(pageNum)、页面大小(pageSize)、分页方法等,以简化在不同表格组件中的重复代码。
74 0