Axios学习笔记

json-server介绍与服务搭建

1.json-server可以帮助我们快速搭建一个HTTP服务
2.在线文档: https://github.com/typicode/json-server
3.使用:
(1)在终端下载: npm install -g json-server
(2)创建数据库 json 文件: db.json
(3)在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" }
}

(4)启动服务器执行命令: json-server --watch db.json
上面那行代码的意思是:启动 json-server 数据去db.json中找
(5)测试
访问所有文档:http://localhost:3000/posts
加上id就是访问指定文档:http://localhost:3000/posts/1

Axios的介绍与页面配置

1.axios:基于promise的http客户端 可以在浏览器和node.js中运行
2.特点:
(1)在浏览器中借助axio可以向服务器发送Ajax请求 在nodejs中可以使用axios向远端发送HTTP请求
(2)支持请求/响应拦截器:可以在发送请求前做一些准备工作 在请求响应回来之后对结果做一些预处理
(3)可以对请求和响应数据做转换
(4)可以取消请求
(5)可以自动将结果转换为json数据
(6)客户端可以防止XSRF攻击
3.文档: https://github.com/axios/axios
4.安装:
(1)在项目中 常在终端使用命令安装:npm install axios或yarn add axios
(2)bower install axios 还需要在页面中通过script标签对其引入
(3)CDN引入 在script标签的src属性中:src=“https://cdn.bootcdn.net/ajax/libs/axios/0.21.1/axios.js”

Axios的基本使用

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>axios的基本使用</title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <script src="https://cdn.bootcdn.net/ajax/libs/axios/0.21.1/axios.js"></script>
</head>
<body>
<div>
    <button>GET请求</button>
    <button>POST请求</button>
    <button>PUT请求</button>
    <button>DELETE请求</button>
</div>
<script>
    // 获取按钮
    const btns = document.querySelectorAll('button')

    // 第一个按钮 请求数据
    btns[0].onclick = function (){
        // 使用axios发送Ajax请求:直接调用axios这个函数 该函数接收一个参数 这个参数是一个对象 该对象中包含一些属性
        axios({
            // 请求类型
            method: 'GET',
            url: 'http://localhost:3000/posts/2'// 这里写我们刚用json-server启动的服务的地址
            // 还可以设置请求头信息等 此处没设置
        }).then(response => {// 因为axios返回的结果是一个promise对象 所以我们可以用then来指定成功的回调
            console.log(response)
        })
    }

    // 第二个按钮 添加一条新的数据
    btns[1].onclick = function (){
        // 使用axios发送Ajax请求:直接调用axios这个函数 该函数接收一个参数 这个参数是一个对象 该对象中包含一些属性
        axios({
            // 请求类型
            method: 'POST',
            url: 'http://localhost:3000/posts', // 这里写资源对应的名称
            // 设置请求体
            data: {
                title: '今天天气不错,还挺风和日丽的',
                author: '张三'
            }
        }).then(response => {// 因为axios返回的结果是一个promise对象 所以我们可以用then来指定成功的回调
            console.log(response)
        })
    }

    // 第三个按钮 更新数据
    btns[2].onclick = function (){
        // 使用axios发送Ajax请求:直接调用axios这个函数 该函数接收一个参数 这个参数是一个对象 该对象中包含一些属性
        axios({
            // 请求类型
            method: 'PUT',
            url: 'http://localhost:3000/posts/3', // 这里写要更新的资源的地址 要加id
            // 设置请求体
            data: {
                title: '今天天气不错,还挺风和日丽的',
                author: '李四'
            }
        }).then(response => {// 因为axios返回的结果是一个promise对象 所以我们可以用then来指定成功的回调
            console.log(response)
        })
    }

    // 第四个按钮 删除数据
    btns[3].onclick = function (){
        // 使用axios发送Ajax请求:直接调用axios这个函数 该函数接收一个参数 这个参数是一个对象 该对象中包含一些属性
        axios({
            // 请求类型
            method: 'DELETE',
            url: 'http://localhost:3000/posts/3', // 这里写要删除的资源的地址 要加id
        }).then(response => {// 因为axios返回的结果是一个promise对象 所以我们可以用then来指定成功的回调
            console.log(response)
        })
    }
</script>
</body>
</html>

Axios其他方式发送请求

通过axios提供的方法发送请求
在这里插入图片描述

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>其他方式发送请求</title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <script src="https://cdn.bootcdn.net/ajax/libs/axios/0.21.1/axios.js"></script>
</head>
<body>
<div>
  <button>GET请求</button>
  <button>POST请求</button>
  <button>PUT请求</button>
  <button>DELETE请求</button>
</div>
<script>
  // 获取按钮
  const btns = document.querySelectorAll('button')

  // 发送get请求
  btns[0].onclick = function (){
    // 使用axios发送Ajax请求:直接调用axios这个函数 该函数接收一个参数 这个参数是一个对象 该对象中包含一些属性
    axios.request({
        // 请求类型
        method: 'GET',
        url: 'http://localhost:3000/comments'// 这里写想要获取的资源的地址
        // 还可以设置请求头信息等 此处没设置
    }).then(response => {// 因为axios.request返回的结果是一个promise对象 所以我们可以用then来指定成功的回调
        console.log(response)
    })
  }

  // 发送post请求
  btns[1].onclick = function (){
      // 使用axios.post发送post请求:axios.post('url',[{请求体 即数据},其他信息])
      axios.post(
          'http://localhost:3000/comments',
          {
              "body": "喜大普奔",
              "postId": 2
          }).then(response => {// 因为axios.post返回的结果是一个promise对象 所以我们可以用then来指定成功的回调
          console.log(response)
      })
  }
</script>
</body>
</html>

请求响应结果的结构

上一节发送get请求后 控制台的输出内容
在这里插入图片描述
1.config:配置对象 包括请求类型 请求url 请求体等
2.data:响应体的结果 是个对象 因为axios自动将服务器返回的结果做了json解析 解析成了一个对象 方便程序员处理结果
3.headers:响应头信息 响应报文包括:响应行 响应头 响应空行 响应体
4.request:原生Ajax请求对象 axios用来发送Ajax请求 而发送Ajax请求就要用到低层的XMLHttpRequest实例对象 request这个属性中保存的就是当前axios在发送请求时 所创建的那个Ajax对象 即XMLHttpRequest实例对象
5.status:响应状态码
6.statusText:响应状态字符串

Axios配置对象详细说明

配置对象指axios/request/get/post等在调用时 他所接收的那个参数对象config

{
  // `url` is the server URL that will be used for the request
  // 给URL发送请求
  url: '/user',

  // `method` is the request method to be used when making the request
  // 设置请求类型
  method: 'get', // default

  // `baseURL` will be prepended to `url` unless `url` is absolute.
  // It can be convenient to set `baseURL` for an instance of axios to pass relative URLs
  // to methods of that instance.
  // 设置url的基础结构 我们在前面发送请求时 写了好几次http://localhost:3000 
  // 我们可以把'http://localhost:3000'配置成baseURL 即baseURL:'http://localhost:3000' 
  // 在设置url时 只需要设置具体路径就可以了 即url: '/comments' 
  // axios内部会自动将baseURL和url进行拼接形成最终的URL(http://localhost:3000/comments)
  baseURL: 'https://some-domain.com/api/',

  // `transformRequest` allows changes to the request data before it is sent to the server
  // This is only applicable for request methods 'PUT', 'POST', 'PATCH' and 'DELETE'
  // The last function in the array must return a string or an instance of Buffer, ArrayBuffer,
  // FormData or Stream
  // You may modify the headers object.
  // 对请求的数据做预处理 将处理后的结果发送给服务器 
  transformRequest: [function (data, headers) {
    // Do whatever you want to transform the data

    return data;
  }],

  // `transformResponse` allows changes to the response data to be made before
  // it is passed to then/catch
  // 对响应的结果做一些改变 我们再用自定义的回调处理改变后的结果
  transformResponse: [function (data) {
    // Do whatever you want to transform the data

    return data;
  }],

  // `headers` are custom headers to be sent
  // 设置请求头信息 在某些项目中 进行身份校验时 他要求你在头信息中加入一个特殊的标识 
  // 然后检验你的请求是否满足条件 此时就可以借助headers对请求头信息进行设置
  headers: {'X-Requested-With': 'XMLHttpRequest'},

  // `params` are the URL parameters to be sent with the request
  // Must be a plain object or a URLSearchParams object
  // 设置url参数 axios会把params对象中的数据变成一个参数字符串 缀到url后边 向服务器发送请求
  params: {
    ID: 12345
  },

  // `paramsSerializer` is an optional function in charge of serializing `params`
  // (e.g. https://www.npmjs.com/package/qs, http://api.jquery.com/jquery.param/)
  // 配置参数序列化 对请求的参数做一个序列化 转化成一个字符串 假如你设置了:
  // params: {
  //  ID: 12345
  // },
  // 默认情况下 会把params转换成http://localhost:3000/comments?ID=12345 
  // 但是有时 服务器可能要求参数这样传递:http://localhost:3000/comments?ID/12345 或
  // http://localhost:3000/comments?ID.12345 这时你就需要在paramsSerializer中设置了
  paramsSerializer: function (params) {
    return Qs.stringify(params, {arrayFormat: 'brackets'})
  },

  // `data` is the data to be sent as the request body
  // Only applicable for request methods 'PUT', 'POST', 'DELETE , and 'PATCH'
  // When no `transformRequest` is set, must be of one of the following types:
  // - string, plain object, ArrayBuffer, ArrayBufferView, URLSearchParams
  // - Browser only: FormData, File, Blob
  // - Node only: Stream, Buffer
  // 设置请求体 有两种形式可以设置:对象形式 字符串形式 如果是对象形式 axios会将其转为json格式字符串进行传递 如果是字符串形式 则直接传递
  // 对象形式
  data: {
    firstName: 'Fred'
  },
  
  // syntax alternative to send data into the body
  // method post
  // only the value is sent, not the key
  // 字符串形式
  data: 'Country=Brasil&City=Belo Horizonte',

  // `timeout` specifies the number of milliseconds before the request times out.
  // If the request takes longer than `timeout`, the request will be aborted.
  // 设置超时时间 如果超过这个时间客户端还没有收到服务器返回的结果 则取消请求 单位毫秒
  timeout: 1000, // default is `0` (no timeout)

  // `withCredentials` indicates whether or not cross-site Access-Control requests
  // should be made using credentials
  // 在跨域请求时 设置是否携带cookie true为携带 false为不携带 
  withCredentials: false, // default

  // `adapter` allows custom handling of requests which makes testing easier.
  // Return a promise and supply a valid response (see lib/adapters/README.md).
  // 设置请求适配器 一种是在浏览器中发送Ajax请求 一种是在node中发送http请求
  adapter: function (config) {
    /* ... */
  },

  // `auth` indicates that HTTP Basic auth should be used, and supplies credentials.
  // This will set an `Authorization` header, overwriting any existing
  // `Authorization` custom headers you have set using `headers`.
  // Please note that only HTTP Basic auth is configurable through this parameter.
  // For Bearer tokens and such, use `Authorization` custom headers instead.
  // 对请求基础验证 设置用户名密码
  auth: {
    username: 'janedoe',
    password: 's00pers3cret'
  },

  // `responseType` indicates the type of data that the server will respond with
  // options are: 'arraybuffer', 'document', 'json', 'text', 'stream'
  //   browser only: 'blob'
  // 设置响应体结果的格式 默认值json
  responseType: 'json', // default

  // `responseEncoding` indicates encoding to use for decoding responses (Node.js only)
  // Note: Ignored for `responseType` of 'stream' or client-side requests
  // 响应结果编码 默认utf8
  responseEncoding: 'utf8', // default

  // `xsrfCookieName` is the name of the cookie to use as a value for xsrf token
  // 设置跨站请求标识 设置cookie名字 这是为了保证请求来自我自己的客户端 而不是来自未知的、其他的页面
  // 起保护作用 为什么能实现保护作用:服务器在返回结果是会给你返回一个唯一的标识 客户端下次发送请求时
  // 需要把这个标识带过去 服务器认了之后 检测没有问题才会给你做响应 为什么能实现保:有一些网站
  // 他页面中会加入一些链接 向我们服务器发送请求 如果你不做这个唯一的标识去检验的话
  // 可能这个页面发送过来的请求就直接对我们的结果产生了影响 而加上唯一标识后
  // 我们的客户端是可以发送请求的 但是其他的网页 他在发送请求时 是没有这个标识的
  // 此时就可以有效避免跨站攻击
  xsrfCookieName: 'XSRF-TOKEN', // default

  // `xsrfHeaderName` is the name of the http header that carries the xsrf token value
  // 设置跨站请求标识 设置头信息名字
  xsrfHeaderName: 'X-XSRF-TOKEN', // default

  // `onUploadProgress` allows handling of progress events for uploads
  // browser only
  // 设置上传时的回调函数
  onUploadProgress: function (progressEvent) {
    // Do whatever you want with the native progress event
  },

  // `onDownloadProgress` allows handling of progress events for downloads
  // browser only
  // 设置下载时的回调函数
  onDownloadProgress: function (progressEvent) {
    // Do whatever you want with the native progress event
  },

  // `maxContentLength` defines the max size of the http response content in bytes allowed in node.js
  // 设置HTTP响应体的最大尺寸 单位字节
  maxContentLength: 2000,

  // `maxBodyLength` (Node only option) defines the max size of the http request content in bytes allowed
  // 设置请求体的最大尺寸
  maxBodyLength: 2000,

  // `validateStatus` defines whether to resolve or reject the promise for a given
  // HTTP response status code. If `validateStatus` returns `true` (or is set to `null`
  // or `undefined`), the promise will be resolved; otherwise, the promise will be
  // rejected.
  // 对响应结果的成功来做一个设置 响应状态码status >= 200 && status < 300则认为成功
  validateStatus: function (status) {
    return status >= 200 && status < 300; // default
  },

  // `maxRedirects` defines the maximum number of redirects to follow in node.js.
  // If set to 0, no redirects will be followed.
  // 最大跳转次数 客户端向某一服务器发送请求时 服务器做了跳转 客户端是否继续请求 默认值5 
  // 客户端跳转5次服务器跟进5次 第6次跳转客户端就不继续请求了 用于node
  maxRedirects: 5, // default

  // `socketPath` defines a UNIX Socket to be used in node.js.
  // e.g. '/var/run/docker.sock' to send requests to the docker daemon.
  // Only either `socketPath` or `proxy` can be specified.
  // If both are specified, `socketPath` is used.
  // 设置socket文件的位置 用于向docker守护进程发送请求 即做数据转发 
  // 如果你设置了socketPath又设置了proxy 则优先使用socketPath
  socketPath: null, // default

  // `httpAgent` and `httpsAgent` define a custom agent to be used when performing http
  // and https requests, respectively, in node.js. This allows options to be added like
  // `keepAlive` that are not enabled by default.
  // 设置客户端信息 如keepAlive: true 是否保持链接
  httpAgent: new http.Agent({ keepAlive: true }),
  httpsAgent: new https.Agent({ keepAlive: true }),

  // `proxy` defines the hostname, port, and protocol of the proxy server.
  // You can also define your proxy using the conventional `http_proxy` and
  // `https_proxy` environment variables. If you are using environment variables
  // for your proxy configuration, you can also define a `no_proxy` environment
  // variable as a comma-separated list of domains that should not be proxied.
  // Use `false` to disable proxies, ignoring environment variables.
  // `auth` indicates that HTTP Basic auth should be used to connect to the proxy, and
  // supplies credentials.
  // This will set an `Proxy-Authorization` header, overwriting any existing
  // `Proxy-Authorization` custom headers you have set using `headers`.
  // If the proxy server uses HTTPS, then you must set the protocol to `https`. 
  // 设置代理 用于node 一般在做爬虫时 如果你用一个ip向目标服务器发送请求 抓取数据的话 
  // 很可能会被别人禁掉你的ip 此时你可以借助中间代理 做上很多代理 疯狂切换 发送请求 
  // 这样就可以很好的获取目标服务器的数据 包括投票之类的 都用到相同的原理 都用到代理
  proxy: {
    protocol: 'https',
    host: '127.0.0.1',
    port: 9000,
    auth: {
      username: 'mikeymike',
      password: 'rapunz3l'
    }
  },

  // `cancelToken` specifies a cancel token that can be used to cancel the request
  // (see Cancellation section below for details)
  // 对Ajax请求做一个取消的设置
  cancelToken: new CancelToken(function (cancel) {
  }),

  // `decompress` indicates whether or not the response body should be decompressed 
  // automatically. If set to `true` will also remove the 'content-encoding' header 
  // from the responses objects of all decompressed responses
  // - Node only (XHR cannot turn off decompression)
  // 是否解压响应结果 true为解压 默认为true 用于node
  decompress: true // default

  // transitional options for backward compatibility that may be removed in the newer versions
  transitional: {
    // silent JSON parsing mode
    // `true`  - ignore JSON parsing errors and set response.data to null if parsing failed (old behaviour)
    // `false` - throw SyntaxError if JSON parsing failed (Note: responseType must be set to 'json')
    silentJSONParsing: true; // default value for the current Axios version

    // try to parse the response string as JSON even if `resposeType` is not 'json'
    forcedJSONParsing: true;
    
    // throw ETIMEDOUT error instead of generic ECONNABORTED on request timeouts
    clarifyTimeoutError: false;
  }
}

Axios的默认配置

1.可以将重复设置设置在默认设置中 来简化代码
2.通过axios.defaults.上一节提到的config对象中的属性来设置

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>axios的默认配置</title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <script src="https://cdn.bootcdn.net/ajax/libs/axios/0.21.1/axios.js"></script>
</head>
<body>
<div>
  <button>GET请求</button>
  <button>POST请求</button>
  <button>PUT请求</button>
  <button>DELETE请求</button>
</div>
<script>
  // 获取按钮
  const btns = document.querySelectorAll('button')

  // 默认配置
  axios.defaults.method = 'GET'// 设置默认的请求类型为get
  axios.defaults.baseURL = 'http://localhost:3000'// 设置基础url
  // axios.default.params = {id: 100}
  // axios.default.timeout = 3000
  // 发送get请求
  btns[0].onclick = function (){
    // 使用axios发送Ajax请求:直接调用axios这个函数 该函数接收一个参数 这个参数是一个对象 该对象中包含一些属性
    axios({
      // method: 'GET',// 请求类型
      // url: 'http://localhost:3000/comments'

      // 设置了默认配置后 代码简化为:
      url: '/comments'// 这里写想要获取的资源的地址
    }).then(response => {// 因为axios返回的结果是一个promise对象 所以我们可以用then来指定成功的回调
      console.log(response)
    })
  }
</script>
</body>
</html>

Axios创建示例对象发送Ajax请求

通过axios.create()创建实例对象 这么做的好处/应用场景:假设A服务器 B服务器都提供了数据服务 当我们给A发送请求时 我们需要设置A的协议 域名 端口号 当我们给B发送请求时 我们需要设置B的协议 域名 端口号 如果我们用默认配置去做的话 那么只能使一个有效 但是我们可以通过axios.create()创建两个示例对象 分别给A B两个服务器发送请求 你想给谁发 就调用哪个对象

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>axios创建示例对象发送Ajax请求</title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <script src="https://cdn.bootcdn.net/ajax/libs/axios/0.21.1/axios.js"></script>
</head>
<body>
<button>GET请求</button>
<button>POST请求</button>
<script>
  // 获取按钮
  const btns = document.querySelectorAll('button')
  // 通过axios.create()创建实例对象 axios.create()中接收一个参数 这个参数就是配置对象 在里面可以设置参数
  const duanzi = axios.create({
    baseURL: 'https://api.apiopen.top',// A服务器的地址
    timeout: 2000
  })

  const B = axios.create({
      baseURL: 'https://b.com',// B服务器的地址(这个地址我是瞎写的)
      timeout: 2000
  })

  // 这里axios.create()创建出来的对象duanzi和axios对象功能几乎是一样的
  duanzi({
    url: '/getJoke'
  }).then(response => {
    console.log(response)
  })

  // 也可以利用封装好的方法发送请求
  duanzi.get('/getJoke').then(response => {console.log(response.data)})// 为了区分 这里用response.data
</script>
</body>
</html>

Axios拦截器

1拦截器就是一些函数 分为请求拦截器 响应拦截器
2.请求拦截器:在发送请求前 我们可以借助回调函数 来对请求的参数和内容来做一些处理和检测 如果都没有问题 再发送请求 如果有问题 这个请求我们可以停止或取消
3.响应拦截器:当服务器返回结果后 我们可以通过自己的回调来处理结果 响应拦截器可以在我们处理结果前 先对结果做一些预处理 比如 可以对失败的结果做一些提醒或处理 对数据结果做一些格式化的处理 如果每日有问题 再交由我们自己的回调函数来处理 如果有问题 可以直接在响应拦截器中处理掉 我们就可以不用处理了
4.拦截器就像一道道关卡 满足条件就放行(请求拦截器发送请求 响应拦截器将数据交由程序员处理 )如果不满足条件 就进行处理

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>axios拦截器</title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <script src="https://cdn.bootcdn.net/ajax/libs/axios/0.21.1/axios.js"></script>
</head>
<body>
  <script>
    // 设置请求拦截器
    // config就是配置对象 再请求拦截器中 我们可以对config进行处理
    axios.interceptors.request.use(function (config) {
      console.log('请求拦截器 成功');
      // 可以再这里修改config的参数 再请求拦截器中 对请求的参数进行设置
      config.params = {a: 100};
      return config;
    }, function (error) {
      console.log('请求拦截器 失败');
      return Promise.reject(error);
    });

    // 设置响应拦截器 response是axios生成的默认的响应结果
    axios.interceptors.response.use(function (response) {
      console.log('设置响应拦截器 成功');
      // 我们可以不处理所有的响应结果 只处理其中的某一个部分 那我们不return response 而return response.data
      // 在这里对响应结果进行处理
      return response.data;// 只处理响应体
    }, function (error) {
      console.log('设置响应拦截器 失败');
      return Promise.reject(error);
    });
    axios({
        method: 'GET',// 请求类型
        url: 'http://localhost:3000/posts'
    }).then(response => {// 因为axios返回的结果是一个promise对象 所以我们可以用then来指定成功的回调
        console.log('自定义回调处理成功的结果')
    }).catch(reject => {
        console.log('自定义回调处理失败的结果')
    })
    // 以上输出:请求拦截器 成功=》设置响应拦截器 成功=》自定义回调处理成功的结果
  </script>
  
  <script>
      // 设置请求拦截器
      axios.interceptors.request.use(function (config) {
          console.log('请求拦截器 成功');
          throw '参数出错'
      }, function (error) {
          console.log('请求拦截器 失败');
          return Promise.reject(error);
      });

      // 设置响应拦截器
      axios.interceptors.response.use(function (response) {
          console.log('设置响应拦截器 成功');
          return response;
      }, function (error) {
          console.log('设置响应拦截器 失败');
          return Promise.reject(error);
      });
      axios({
          method: 'GET',// 请求类型
          url: 'http://localhost:3000/posts'
      }).then(response => {// 因为axios返回的结果是一个promise对象 所以我们可以用then来指定成功的回调
          console.log('自定义回调处理成功的结果')
      }).catch(reject => {
          console.log('自定义回调处理失败的结果')
      })
      // 以上输出:请求拦截器 成功=》设置响应拦截器 失败=》自定义回调处理失败的结果
  </script>
  
  <script>
      // 设置请求拦截器
      axios.interceptors.request.use(function (config) {
          console.log('请求拦截器 成功-1');
          return config;
      }, function (error) {
          console.log('请求拦截器 失败-1');
          return Promise.reject(error);
      });
      axios.interceptors.request.use(function (config) {
          console.log('请求拦截器 成功-2');
          return config;
      }, function (error) {
          console.log('请求拦截器 失败-2');
          return Promise.reject(error);
      });

      // 设置响应拦截器
      axios.interceptors.response.use(function (response) {
          console.log('设置响应拦截器 成功-1');
          return response;
      }, function (error) {
          console.log('设置响应拦截器 失败-1');
          return Promise.reject(error);
      });
      axios.interceptors.response.use(function (response) {
          console.log('设置响应拦截器 成功-2');
          return response;
      }, function (error) {
          console.log('设置响应拦截器 失败-2');
          return Promise.reject(error);
      });

      axios({
          method: 'GET',// 请求类型
          url: 'http://localhost:3000/posts'
      }).then(response => {// 因为axios返回的结果是一个promise对象 所以我们可以用then来指定成功的回调
          console.log('自定义回调处理成功的结果')
      }).catch(reject => {
          console.log('自定义回调处理失败的结果')
      })
      // 以上输出:请求拦截器 成功-2=》请求拦截器 成功-1=》设置响应拦截器 成功-1=》设置响应拦截器 成功-2=》自定义回调处理成功的结果
      // 请求拦截器后进先执行 响应拦截器先进先执行
  </script>
</body>
</html>

Axios取消请求

让服务器延迟2s再响应json-server --watch db.json -d 2000json-server --watch db.json --delay 2000
如果不让服务器延迟响应的话 请求一发出去我们还没取消 就获得了结果 没什么效果

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>取消请求</title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <script src="https://cdn.bootcdn.net/ajax/libs/axios/0.21.1/axios.js"></script>
</head>
<body>
<div>
  <button>发送请求</button>
  <button>取消请求</button>
</div>
<script>
  // 获取按钮
  const btns = document.querySelectorAll('button')
  // 2.声明全局变量
  let cancel = null;
  // 发送请求
  btns[0].onclick = function (){
    axios({
      method: 'GET',
      url: 'http://localhost:3000/comments',
      // 取消请求
      // 1.添加配置对象的属性
      cancelToken: new axios.CancelToken(function executor(c) {
        // 3.将c的值赋值给cancel
        cancel = c;
      })
    }).then(response => {// 因为axios返回的结果是一个promise对象 
    // 所以我们可以用then来指定成功的回调
      console.log(response)
      // 4.将cancel的值初始化 请求回来之后 将cancel复原 这样你下次发送请求时 
      // 在请求的过程中(请求未完成) cancel为null
      cancel = null
    })
  }
  // 5.绑定第2个事件 取消请求
  btns[1].onclick = function (){
    cancel();
  }
</script>
</body>
</html>

在抢购的时候 用户疯狂点击 疯狂发请求 服务器压力很大 那么我们可以在每次发请求前检测一下是不是正在发请求 如果有 则取消掉 重新发请求 和防抖一个原理

<script>
  // 获取按钮
  const btns = document.querySelectorAll('button')
  // 2.声明全局变量
  let cancel = null;
  // 发送请求
  btns[0].onclick = function (){
    // 检测上一次的请求是否已经完成 通过判断cancel的值是不是null来判断请求是否完成 
    // 因为我们执行完axios后 会将c的值赋值给cancel
    if (cancel) {
      cancel();// 取消上一次的请求
    }
    axios({
      method: 'GET',
      url: 'http://localhost:3000/comments',
      // 取消请求
      // 1.添加配置对象的属性
      cancelToken: new axios.CancelToken(function executor(c) {
        // 3.将c的值赋值给cancel
        cancel = c;
      })
    }).then(response => {// 因为axios返回的结果是一个promise对象 
    // 所以我们可以用then来指定成功的回调
      console.log(response)
      // 4.将cancel的值初始化 请求回来之后 将cancel复原 这样你下次发送请求时 
      // 在请求的过程中(请求未完成) cancel为null
      cancel = null
    })
  }
  // 5.绑定第2个事件 取消请求
  btns[1].onclick = function (){
    cancel();
  }
</script>

二次封装

一、基本封装需要做哪些
请添加图片描述
二、在src文件夹下新建axios.js文件,用于基本全局配置、token、密钥、响应的统一基本处理,代码如下:

//配置全局得基础配置
import axios from "axios";// 引入axios
//配置中心
import webConfig from "@/global.config.js"
//base64
import { Base64 } from "js-base64"
import router from "@/router";
//baseURL,timeout,header,responseType,withCredentials
//后面的请求用request来发
let request = axios.create({
    //1,基础配置
    baseURL: "http://localhost:8000/",
    timeout: 30 * 1000,
    responseType: "json",
    headers: {
        "a": "123"
    }
})
request.interceptors.request.use((config) => {
    //token,密钥得设置
    let whiteList = webConfig.whiteListApi
    let url = config.url// 本次请求的url
    // 假设token存在localStorage里面,先判断一下localStorage里有没有token
    let token = localStorage.getItem("token");
    if (whiteList.indexOf(url) === -1 && token) {
    	// 判断本次请求的url是否在白名单里,如果不在,表明本次请求需要token
        config.headers.token = token;
    }
    //密钥-secretId+特殊算法
    let _secret = Base64.encode(webConfig.secretId + new Date().toString());
    config.headers.secret = _secret;
    return config;
}, error => {
    return Promise.reject(new Error(error))
})
request.interceptors.response.use((res) => {
    //响应得统一处理
    const status = res.data.code || 200
    const message = res.data.msg || "未知错误";
    if (status === 401) {
        alert("你没有权限");
        router.push("/about")
        return Promise.reject(new Error(message));
    }
    if (status !== 200) {
        alert("错误码" + status + "   " + message);
        return Promise.reject(new Error(message));
    }
    return res;
}, error => {
    //真实项目中,往往使用组件库得消息提示 $waring
    alert(error)
    return Promise.reject(new Error(error));
})
export default request;

src文件夹下新建global.config.js文件,用于全局配置,具体代码如下:

export default {
    whiteListApi: ["/a", "/b"],// 不需要验证token的URL配在这里
    secretId: "helloworld",// 加密密钥
    pageSize: [20, 40, 80]
}

在src文件夹下新增api文件夹用于封装请求方法,一般项目中都是分模块的,在api文件夹下根据模块新建js文件,比如有用户模块,就新增user.js,有商城模块,就新增shop.js。user.js具体代码如下:

import { request } from "./request"
export const getList = (params) => {
    return request({
        url: "/getList",
        method: "get",
        params: {
            ...params
        }
    })
}

在vue中使用:

import HelloWorld from '@/components/HelloWorld.vue'
import { getList } from "@/api/user"

export default {
  name: 'Home',
  components: {
    HelloWorld
  },
  mounted() {

  },
  methods: {
    getList() {
      getList().then((res) => {
        console.log(res);
      })
    }
  }
}

三、扩展:我们通过发现业务中的一些请求相关的处理时经常重复进行的,不妨把他封装进来,让请求更加简便:

  1. 防止频繁提交:很多按钮都需要进行防止频繁提交的操作,每次都要写一遍代码很冗余,直接把节流功能封装到request中,
  2. 缓存数据

在api文件夹下新增request.js用于添加额外功能,具体代码如下:

import request from "@/axios";
let myRequest = (function () {
    let mem = {};//Map对象更合适
    let hasRequest = [];
    return function (config) {
        let url = config.url
        if (mem[url]) {
        	// 如果已经有这个接口的缓存数据了,直接返回数据,否则发起请求
            return Promise.resolve(mem[url]);
        } else {
            if (hasRequest.indexOf(url) !== -1) {
                return Promise.reject({ mes: "请求已经提交" })
            }
            hasRequest.push(url);
            return request({
                ...config
            }).then((res) => {

                hasRequest = hasRequest.filter((item) => {
                    if (item !== url) {
                        return item;
                    }
                })
                // 缓存数据:每次请求完成,将响应数据保存在mem中
                mem[url] = res;
                return res
            })
        }
    }
})()
export {
    myRequest as request,// 具备扩展功能的request
    request as initRequest// 不具备扩展功能的request
}

用法同前述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值