“This is the fourth day of my participation in the Gwen Challenge in November. Check out the details: The Last Gwen Challenge in 2021.”

preface

There are many online request to packaging, can through the interception of the request, the request parameters, request header, the return value, modified, or even cancel the request, or retransmission request, the request parameter encryption, authentication and so on, the basic request for every mature project encapsulation, plan a lot, people prefer a USES the hook to intercept request do all kinds of processing, Instead of talking about that, let’s talk about encapsulating how interfaces are called.

Common invocation methods

No packaged version

Using axios as an example, call the interface directly using post, get, and delete. Look at this code:

axios.post(url, {data}).then(res=>{})
Copy the code

So write, URL each page have to write once, in case the background link is changed, do not change the trouble? Even if you could do it globally, the people in the back, maintaining the same functionality, different pages, would have to copy this code everywhere.

premium

On the basis of the previous request link unified write in a JS file, in use by introducing the way to use

// static.js export default { aLink: 'xxx', bLink: Import url from 'static.js' axios.post(url.alink, {data}).then(res=>{})Copy the code

Look at the code, not much has changed, but a little bit more

Take a look at this version

Each request is actually a promise, and if you put that promise in one place, where you call it, you just introduce it, you don’t have to repeat that code. Here’s an example:

// loginApi.js const S_URL = { login: '/api/login', reg: '/api2/reg' } export login () { return axios.post(S_URL.login, Import {login} from 'loginapi.js' login.then(res=>{})Copy the code

This version has no problem to load on demand, but also to achieve a unified management, to change the time to change a good. But I am a little lazy, each call place have to introduce once, a page interface a bunch, not willing to introduce one by one, so personal hobby version.

Personal Hobby Edition

You don’t like to import them one by one, you import them globally at a time, and then you attach them to global variables, you can attach them to vue objects, you can attach them to Windows, you can attach them to global variables, I attach them to Vue objects.

Look at the code

// storeCouponInfo: {method: 'post', url: '/ stores/stores/coupon/storeCouponInfo', / / here may also have some other configurations, such as whether to uniform error processing},}Copy the code

This is where you can import all apis from the apis folder through the js method (see require.context if not clear).

// api.js
import store from './apis/storeApi.js'
import MyHttp from './req'
const ALL_API = Object.assign({}, storeApi)
const api = new MyHttp({}, ALL_API)
export default api
Copy the code

There is some processing going on in req.js

// req.js import axios from 'axios' let axiosInstance let typeOf = typeof Symbol === 'function' && typeof Symbol.iterator === 'symbol' ? function (obj) { return typeof obj } : function (obj) { return obj && typeof Symbol === 'function' && obj.constructor === Symbol && obj ! == Symbol.prototype ? 'symbol' : Typeof obj} */ let refreshSubscribers = [] window. IsRefreshing = false [function(token){}, function(token){},... */ function subscribeTokenRefresh(cb) { refreshSubscribers.push(cb); } /* The request in the array is executed after the new token is obtained. Checksum */ function onchecksum (token) {console.log('onRefreshedvvvvvv-- >', refreshSubscribers) refreshSubscribers.map(cb => cb(token)); Constructor () {constructor() {axiosInstance = axios.create({baseURL: process.env.VUE_APP_BASE_API, timeout: 30000, headers: { 'Content-Type': 'application/x-www-form-urlencoded; Charset = utf-8 '}}) / / add request interceptor axiosInstance. Interceptors. Request. Use (function (config) {the console. The log (' config - > ', config) let { isLoading } = config.options if (config.method === 'get' && config.data) { config.params = config.data } Loading if (isLoading) {global.toast.loading({message: 'Loading... ', forbidClick: true, duration: 30000 }) } return config }, Function (error) {return Promise. Reject (error)}) / / add the response interceptor axiosInstance. Interceptors. Response. Use ((response) = > { global.toast.clear() if (! response || ! response.data) return Promise.reject(response) let res = response.data let _this = this switch (res.code) { case 0: return res case 2000: case 2007: switch (response.config.url) { case '/generateTokenByCustom': return Promise.reject(res) default: Var the userInfo = global. LStore. Get (global) lStore. StaticName. USER_INFO) if (the userInfo && the userInfo. Id) {/ / to prevent the problem of multiple requests need token if (! window.isRefreshing) { window.isRefreshing = true global.api.generateTokenByCustom({ accountId: userInfo.id }, { dealException: True}). Then (result = > {try {/ storage/token. Global token. = the result data. The token global. The addon. RefreshToken ({token: Token}) // Refresh the field with the checksum (result.data.token) window.isRefreshing = false} catch (error) { Console. log(error) global.toast(' Login failed, Reject (error)}})} let retry = new Promise((resolve) => {/*(token) => {... } {let {url, method, data, headers, Options} = response.config data = js.parse (data) headers. Token = "Bearer "+ token /* Suspend requests */ resolve(_this.sendRrquest(url, method, data, headers, options)) }) }) return retry } break } break default: if (res.message ! == 'success') { console.log('err:', res) let { dealException } = response.config.options || {} if (! DealException) {global. Toast (res) message | | 'service is busy, Please try again later ')} return promise.reject (res)} break}}, error => {global.toasts. Clear () console.log('error: ', error) global. Toast (' Service busy, ') return promise.reject (error)})} isObject(obj) {return (typeof obj === 'undefined'? 'undefined' : typeOf(obj)) === 'object' && obj ! For (var _len = arguments.length, args = Array(_len > 1? _len - 1 : 0), _key = 1; _key < _len; _key++) { args[_key - 1] = arguments[_key] } if (this.isObject(obj) && args.length > 0) { if (Object.assign) { return Object.assign.apply(Object, [obj].concat(args)) } args.forEach(function (arg) { if (this.isObject(arg)) { Object.keys(arg).forEach(function (key) { obj[key] = arg[key] }) } }) } return obj } sendRrquest(url, method, data, header, options) { return axiosInstance({ method: method, url: url, data: data, headers: Header, options})}} let myRequest = new myRequest () ALL_API) { let resource = {} for (let actionName in ALL_API) { let _config = ALL_API[actionName] // Options: contains (pathParam: URL parameter, dealException: whether to process error information separately, isLoading: Whether Loading is displayed, ContentType Request type) Resource [actionName] = (pdata, options = {}) => {let paramsData = myRequest.extend({}, defaultParams, Pdata) let url = _config.url if (options.pathParam) {url = url + options.pathParam} // Let head = { 'Content-Type': options.contentType || 'application/json; charset=UTF-8' } switch (url) { case '/generateTokenByCustom': delete head.token return myRequest.sendRrquest(url, _config.method, paramsData, head, options) default: if (global.token) { head.token = "Bearer " + global.token // console.log(head.token) } else{ delete head.token } return myRequest.sendRrquest(url, _config.method, paramsData, head, options) } } } return resource } export default MyHttpCopy the code

If you look at the MyHttp method, all of our requests are going to go through here, and there is also pre-processing for the request, depending on your needs.

In the end, binding is easy. Just do it in main.js, wherever you like

global.api = api
Vue.prototype.api = api
Copy the code

Finally, I spread the idea of being lazy and welcome more comfortable solutions to share and discuss.