react中請求介面的封裝

w39發表於2021-09-09
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中 :


// Creates a new URL by combining the specified URLs
const combineURL = (baseUrl, path) => {
  return `${baseUrl.replace(//+$/, '')}/${path.replace(/^/+/, '')}`;
};

export default combineURL;

combineURL.js中 :

// Creates a new URL by combining the specified URLsconst combineURL = (baseUrl, path) => {  return `${baseUrl.replace(//+$/, '')}/${path.replace(/^/+/, '')}`;
};export default combineURL;

isAbsoluteURL.js中 :

// A URL is considered absolute if it begins with "://" or "//" (protocol-relative URL).// RFC 3986 defines scheme name as a sequence of characters beginning with a letter and followed// by any combination of letters, digits, plus, period, or hyphen.//  isAbsoluteURL = (url) => /^([a-z][a-zd+-.]*:)?///i.test(url);export default isAbsoluteURL;

serialize.js中 :

import { isPresent } from 'lib/lang';const encode = (value) => {  return encodeURIComponent(value)
    .replace(/%40/gi, '@')
    .replace(/%3A/gi, ':')
    .replace(/%24/g, '$')
    .replace(/%2C/gi, ',')
    .replace(/%20/g, '+')
    .replace(/%5B/gi, '[')
    .replace(/%5D/gi, ']');
};// Encode a set of form elements as a string for submission.const serialize = (params) => {  const ret = [];  Object.keys(params).forEach(key => {    const value = params[key];    if (isPresent(value)) {
      ret.push(`${encode(key)}=${encode(value)}`);
    }
  });  return ret.join('&');
};export default serialize;
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;
    }    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同級。

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 factoryfunction 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 factoryconst createHeaders = () => {  const headers = {
    ...request.defaults.headers,
  };  // const auth = JSON.parse(localStorage.getItem('auth'+sessionStorage.getItem("hid")));
  
  // const token = sessionStorage.getItem('token'); //  登入location獲取到的token存放l
  
  
  // if (auth) {
  //   // Toast.info(`請稍等: ${token}`, 2);
  //   // Toast.loading('');
    
  //   headers.Authorization = auth.Token;
  // } else if (token) {
  //   // ;
  //   // Toast.info(`請稍等: ${token}`, 2);
  //   // Toast.loading('');
  //   headers.Authorization = token;
    
  // }
  headers.Authorization = "app";  return headers;
};// Request interceptorfunction 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 */// sugerrequest.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: "",
};

之後再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 });
}

         




作者:sidney_c
連結:


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/854/viewspace-2814447/,如需轉載,請註明出處,否則將追究法律責任。

相關文章