Small knowledge, big challenge! This article is participating in the creation activity of “Essential Tips for Programmers”.

This article has participated in the “Digitalstar Project” and won a creative gift package to challenge the creative incentive money.

1. Create your own API

1.1 Classification of apis

  1. REST APIS: restful (Representational State Transfer layer State transformation)
  • (1) The operation of SENDING a request for CRUD is determined by the request mode
  • (2) Multiple operations can be performed on the same request path
  • (3) The request method will use GET/POST/PUT/DELETE
  1. The REST API: restless
  • (1) The request mode does not determine the REQUESTED CRUD operation
  • (2) One request path corresponds to only one operation
  • (3) Generally only GET/POST

1.2 Setting up REST APIS using JSON-server

1.2.1 What is jSON-server?

A toolkit for quickly building REST apis

1.2.2 using json – server

  1. Online documentation: https://github.com/typicode/json-server

  2. NPM install -g json-server

  3. Create a database JSON file in the target root directory: db.json

{
	"posts": [{"id": 1."title": "json-server"."author": "typicode" },
		{ "id": 2."title": "json-server2"."author": "typicode"}]."comments": [{"id": 1."body": "some comment"."postId": 1}]."profile": { "name": "typicode"}}Copy the code
  1. Run the following command to start the server:json-server --watch db.json

1.2.3 Using a browser to access the test

http://localhost:3000/posts

http://localhost:3000/posts/1

1.2.4 Using AXIOS to access tests

<! DOCTYPEhtml>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="Width = device - width, initial - scale = 1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>
<body>
  <div>
    <button onclick="testGet()">A GET request</button>
    <button onclick="testPost()">A POST request</button>
    <button onclick="testPut()">PUT request</button>
    <button onclick="testDelete()">The DELETE request</button>
  </div>

  <script src="https://cdn.bootcdn.net/ajax/libs/axios/0.21.1/axios.js"></script>
  <script>
    function testGet() {
      axios.get('http://localhost:3000/posts') // Return an array containing two objects
      / / axios. Get (' http://localhost:3000/posts/1 ') / / returns an object
      // axios.get('http://localhost:3000/posts? Id =1') // Returns an array containing an object
      .then(response= > {
        console.log('/posts get', response.data)
      })
    }

    function testPost() { // Add data
      axios.post('http://localhost:3000/posts', {"title": "json-server3"."author": "typicode" })
      .then(response= > {
        console.log('/posts put', response.data)
      })
    }

    function testPut() { // Update data
      axios.put('http://localhost:3000/posts/3', {"title": "json-server_put"."author": "typicode" })
      .then(response= > {
        console.log('/posts post', response.data)
      })
    }

    function testDelete() { // Delete data
      axios.delete('http://localhost:3000/posts/3')
      .then(response= > {
        console.log('/posts delete', response.data)
      })
    }
  </script>
</body>
</html>
Copy the code

2. Ajax encapsulation of XHR (simple version of Axios)

2.1 the characteristics of

  1. The return value of the function ispromiseThe result of success isresponse, the result of failure iserror
  2. Can handle multiple types of requests: GET/POST/PUT/DELETE
  3. The parameter to the function is a configuration object
{
	url: ' '.// Request an address
	method: ' '.// Request mode GET/POST/PUT/DELETE
	params: {}, // GET/DELETE The query parameter of the request
	data: {}, // POST/PUT Request body parameters
}
Copy the code
  1. The response JSON data is automatically parsed into JS objects/arrays

2.2 Coding Implementation

function axios({
  url,
  method='GET',
  params={},
  data={}
}){
  // Return a Promise object
  return new Promise((resolve, reject) = > {

    // Handle method with uppercase
    method = method.toUpperCase();

    // Process the query argument (concatenated to the URL) id=1&xxx= ABC
    let queryString = ' ';
    Object.keys(params).forEach(key= > {
      queryString += `${key}=${params[key]}& `
    });
    if(queryString){
      // Remove the last '&'
      queryString = queryString.substring(0, queryString.length-1)
      / / received a url
      url += '? ' + queryString
    }

    // 1. Perform asynchronous Ajax requests
    // Create an XHR object
    const request = new XMLHttpRequest();
    // Open the connection (initializes the request, no request)
    request.open(method, url, true);
    // Send the request
    if(method === 'GET' || method === 'DELETE'){
      request.send()// undefined
    } else if (method === 'POST' || method === 'PUT') {// Set the request header to tell the server that the request body is in JSON format
      request.setRequestHeader('Content-Type'.'appliaction/json; charset=utf-8'); 
      // Send request parameters in JSON format
      request.send(JSON.stringify(data)); // Execute asynchronously
    }
    
    // Bind the state change listener
    request.onreadystatechange = function() { // Synchronize execution
      // If the request is not completed, end it
      if(request.readyState ! = =4) {
        return;
      }
      // If the response status code is between [200, 300], it indicates success; otherwise, it fails
      const {status, statusText} = request
      if( status>= 200 && status<=299) {// 2.1 If the request succeeds, call resolve()
        // Prepare the resulting data object response
        const response = {
          data: JSON.parse(request.response),
          status,
          statusText
        };
        resolve(response);
      } else {Call reject() if the request fails
        reject(new Error('request error status is '+ status)); }}})}Copy the code

2.3 Use Test

// 1. GET request: obtain data from the server
function testGet() {
  axios({
    url: 'http://localhost:3000/posts'.method: 'GET'.params: {id: 1.xxx: 'abc'
    }
  }).then(
    response= > {
      console.log(response)
    },
    error= > {
      alert(error.message)
    }
  )
}

// 2. POST request: Add data to the server
function testPost() {
  axios({
    url: 'http://localhost:3000/posts'.method: 'POST'.data: {
      "title": "json-server_post"."author": "typicode_post"
    }
  }).then(
    response= > {
      console.log(response)
    },
    error= > {
      alert(error.message)
    }
  )
}
// 3. PUT request: The server updates data
function testPut() {
  axios({
    url: 'http://localhost:3000/posts/1'.method: 'PUT'.data: {
      "title": "json-server_put"."author": "typicode_put"
    }
  }).then(
    response= > {
      console.log(response)
    },
    error= > {
      alert(error.message)
    }
  )
}

// 3. DELETE request: the server deletes data
function testDelete() {
  axios({
    url: 'http://localhost:3000/posts/2'.method: 'delete'
  }).then(
    response= > {
      console.log(response)
    },
    error= > {
      alert(error.message)
    }
  )
}
Copy the code

3. Understanding and using axios

3.1 What is Axios?

  1. The most popular ajax request library on the front end
  2. React/Vue officially recommends using Axios to make Ajax requests
  3. Documents: https://github.com/axios/axios

3.2 axios characteristics

  1. Asynchronous Ajax request library based on XHR + Promise
  2. It can be used on both the browser and Node sides
  3. Support for request/response interceptors
  4. Support request cancellation
  5. Request/response data transformation
  6. Send multiple requests in batches

3.3 Axios Common syntax

  • Axios (config): generic/essential way to send any type of request

  • Axios (url[, config]): You can specify only the URL to send a GET request

  • Axios.request (config): equivalent to axios(config)

  • Axios.get (url[, config]): sends a GET request

  • Axios.delete (url[, config]): sends a DELETE request

  • Axios. post(URL [, data, config]): sends a POST request

  • Axios. put(URL [, data, config]): sends a PUT request

  • Axios.defaults. XXX: Default global configuration for requests (method\baseURL\params\timeout…)

  • Axios. Interceptors. Request. Use () : add request interceptor

  • Axios. Interceptors. Response. Use () : add response interceptors

  • Axios.create ([config]): Creates a new axios(it does not have the following functionality)

  • Axios.cancel (): Used to create an error object to Cancel the request

  • Axios.canceltoken (): The token object used to create the cancellation request

  • Axios.iscancel (): Whether it was an error to cancel the request

  • Axios.all (Promises): For batch execution of multiple asynchronous requests

  • Axios.spread (): Method used to specify the callback function that receives all success data

3.4 Understanding and use of difficult grammar

3.4.1 trackaxios.create(config)

  1. A new AXIOS is created based on the specified configuration, that is, each new AXIOS has its own configuration

  2. The new Axios just doesn’t have a way to cancel requests or batch them, and everything else is the same syntax

  3. Why was this syntax designed?

    (1) Requirements: The configuration of some interfaces in the project is different from that of other interfaces, how to deal with it (for example, multiple baseURL needs to be specified)

    (2) Solution: Create two new AXIos, each with its own unique configuration, to be applied to interface requests with different requirements

const instance = axios.create({ // instance is a function type
	baseURL: 'http://localhost:3000'
})
// Use instance to send Ajax requests
instance({
	url: '/posts'
})
instance.get('/posts')
Copy the code

3.4.2 Call order of interceptor function/Ajax request/request callback function

  1. Description: Callaxios()Instead of sending the Ajax request immediately, you need to go through a longer process
  2. Flow: Request interceptor 2 => Request interceptor 1 => send ajax request => respond to interceptor 1 => respond to interceptor 2 => callback of the request
  3. Note: This flow is strung together by promises, which the request interceptor passesconfigThe response interceptor passes isresponse
// Add two request interceptors (callback functions)
axios.interceptors.request.use(
  config= > {
    console.log('request interceptor1 onResolved()') / / -- -- -- -- -- -- -- -- -- -- - 2
    return config
  },
  error= > {
    console.log('request interceptor1 onRejected()')
    return Promise.reject(error)
  }
)

axios.interceptors.request.use(
  config= > {
    console.log('request interceptor2 onResolved()') / / -- -- -- -- -- -- -- -- -- -- - 1
    return config
  },
  error= > {
    console.log('request interceptor2 onRejected()')
    return Promise.reject(error)
  }
)

// Add two response interceptors
axios.interceptors.response.use(
  resopnse= > {
    console.log('response interceptor1 onResolved()') / / -- -- -- -- -- -- -- -- -- -- - 3
    return resopnse
  },
  error= > {
    console.log('response interceptor1 onRejected()')
    return Promise.reject(error)
  }
)

axios.interceptors.response.use(
  resopnse= > {
    console.log('response interceptor2 onResolved()') / / -- -- -- -- -- -- -- -- -- -- - 4
    return resopnse
  },
  error= > {
    console.log('response interceptor2 onRejected()')
    return Promise.reject(error)
  }
)

axios.get('http://localhost:3000/posts')
  .then(response= > {
    console.log('data', response.data) //data Array(4) -------------5
  })
  .catch(error= > {
    cosole.log('error', error.message)
  })

// request interceptor2 onResolved()
// request interceptor1 onResolved()
// response interceptor1 onResolved()
// response interceptor2 onResolved()
// data Array(4)
Copy the code

3.4.3 Canceling a Request

1. Basic process

  1. configurationcancelTokenobject
  2. The cache is used to cancel the requestcancelfunction
  3. Called later at a specific timecancelFunction cancel request
  4. Determine if in error callbackserrorcancelAnd do the corresponding processing

2. Implement functions

With Express, set up a server with latency

const express = require('express')
const cors = require('cors')

const app = express()

// Use CORS to allow cross-domain
app.use(cors())
// Can parse urlencode post request body parameters
app.use(express.urlencoded())
// Parse request body parameters in JSON format
app.use(express.json())

app.get('/products1'.(req, res) = > {
  
  setTimeout(() = > {
    res.send([
      {id: 1.name: 'product1.1'},
      {id: 2.name: 'product1.2'},
      {id: 3.name: 'product1.3'}}]),1000 + Math.random()*2000);
  
})

app.get('/products2'.(req, res) = > {

  setTimeout(() = > {
    res.send([{
        id: 1.name: 'product2.1'
      },
      {
        id: 2.name: 'product2.2'
      },
      {
        id: 3.name: 'product2.3'}}]),1000 + Math.random() * 2000);

})

app.listen(4000.() = > {
  console.log('server app start on port 4000')})Copy the code
  1. Click the button to cancel a request in progress
let cancel // The function used to save the cancellation request
function getProducts1() {
  axios({
    url: 'http://localhost:4000/products1'.cancelToken: new axios.CancelToken(function executor(c){ // c is the function used to cancel the current request
      // Save the cancel function, which may need to cancel the current request later
      cancel = c;
    })
  }).then(
    response= > {
      cancel = null
      console.log('Request 1 is successful', response.data)
    },
    error= > {
      cancel = null
      console.log('Request 1 failed', error.message, error) // Request 1 failed force Cancel request Cancel {message: "force Cancel request "}})}function getProducts2() {
  axios({
      url: 'http://localhost:4000/products2'
  }).then(
    response= > {
      console.log('Request 2 is successful', response.data)
    }
  )
}

function cancelReq() {
  // alert(' cancel request ')
  // Execute the function to cancel the request
  if (typeof cancel === 'function'){
    cancel('Force cancel request')}else {
    console.log('No cancelable request')}}Copy the code

  1. Before requesting an interface, cancel a previous incomplete request
let cancel // The function used to save the cancellation request
function getProducts1() {
  // Cancel pending requests before you are ready to send them
  if (typeof cancel === 'function'){
    cancel('Cancel request')
  }
  axios({
    url: 'http://localhost:4000/products1'.cancelToken: new axios.CancelToken(function executor(c){ // c is the function used to cancel the current request
      // Save the cancel function, which may need to cancel the current request later
      cancel = c;
    })
  }).then(
    response= > {

      cancel = null
      console.log('Request 1 is successful', response.data)
    },
    error= > {
      if (axios.isCancel(error)){
        console.log('Error requesting 1 to cancel', error.message)
      }else{ // The request is in error
        cancel = null
        console.log('Request 1 failed', error.message, error) // Request 1 failed force Cancel request Cancel {message: "force Cancel request "}}})}function getProducts2() {
// Cancel pending requests before you are ready to send them
  if (typeof cancel === 'function'){
    cancel('Cancel request')
  }
  axios({
      url: 'http://localhost:4000/products2'.cancelToken: new axios.CancelToken(function executor(c){ 
      cancel = c;
    })
  }).then(
    response= > {
      cancel = null
      console.log('Request 2 is successful', response.data)
    },
    error= > {
      if (axios.isCancel(error)){
        console.log('Error requesting 2 to cancel', error.message)
      }else{ 
        cancel = null
        console.log('Request 2 failed', error.message, error) 
      }
    }
  )
}
function cancelReq() {
  // alert(' cancel request ')
  // Execute the function to cancel the request
  if (typeof cancel === 'function'){
    cancel('Force cancel request')}else {
    console.log('No cancelable request')}}Copy the code

Use interceptors to improve code and reduce code duplication

// Add request interceptor
axios.interceptors.request.use((config) = > { // Write only one successful callback
  // Cancel pending requests before you are ready to send them
  if (typeof cancel === 'function'){
    cancel('Cancel request')}// Add a cancelToken configuration
  config.cancelToken = new axios.CancelToken(function executor(c){ // c is the function used to cancel the current request
      // Save the cancel function, which may need to cancel the current request later
      cancel = c;
    })
    return config
})

// Add a response interceptor
axios.interceptors.response.use(
  response= > { // Successful callback
    cancel = null 
    return response
  },
  error= > { // Failed callback
    if (axios.isCancel(error)){ // Error requesting cancellation
        console.log('Error requesting cancellation', error.message)
        // Break the Promise chain
        return new Promise(() = >{})}else{ // The request is in error
      cancel = null 
      // Pass the error down
      // throw error
      return Promise.reject(error)
    }
  }
)

let cancel // The function used to save the cancellation request
function getProducts1() {
  axios({
    url: 'http://localhost:4000/products1'
  }).then(
    response= > {
      console.log('Request 1 is successful', response.data)
    },
    error= > { // Only handle request failure, cancel request error is not handled
      console.log('Request 1 failed', error.message, error) 
    }
  )
}

function getProducts2() {
  axios({
      url: 'http://localhost:4000/products2'
  }).then(
    response= > {
      console.log('Request 2 is successful', response.data)
    },
    error= > {
      console.log('Request 2 failed', error.message, error) 
    }
  )
}
function cancelReq() {
  if (typeof cancel === 'function'){
    cancel('Force cancel request')}else {
    console.log('No cancelable request')}}Copy the code