• axios使用


    axios

    1、文档

    axios中文文档地址

    2、定义、特性、使用

    2.1 什么是axios

    Axios 是一个基于promiseHTTP库 ,可以用在浏览器和node

    2.2 特性 (重点)

    1. 从浏览器中创建 XMLHttpRequests
    2. node.js 创建 http 请求
    3. 支持 Promise API
    4. 拦截请求和响应
    5. 转换请求数据和响应数据
    6. 取消请求
    7. 自动转换 JSON 数据
    8. 客户端支持防御 XSRF
    2.2.1 XMLHttpRequests

    XMLHttpRequest(XHR)对象用于与服务器交互。
    通过 XMLHttpRequest 可以在不刷新页面的情况下请求特定 URL,获取数据。
    这允许网页在不影响用户操作的情况下,更新页面的局部内容。

    前段局部刷新的底层就是靠XHR对象

    2.2.2 nodejs创建http请求
    // 调用 HTTP 模块
    const http = require("http");
    
    // 创建 HTTP 服务器并监听 8000 端口的所有请求
    http
      .createServer((request, response) => {
        // 用 HTTP 状态码和内容类型来设定 HTTP 响应头
        response.writeHead(200, { "Content-Type": "text/plain" });
    
        // 发送响应体 "Hello World"
        response.end("Hello World\n");
      })
      .listen(8000);
    
    // 在控制台打印访问服务器的 URL
    console.log("服务器运行于 http://127.0.0.1:8000/");
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    2.2.3 支持 Promise API
    1. 看源码、支持Promise 是因为 底层就是Promise 搞的
      在这里插入图片描述
    2. Promise MDN 点这个 在这里插入图片描述
    2.2.4 拦截请求和响应

    axios中有拦截器 请求拦截和响应拦截

    1. 添加拦截器:在请求或响应被 then 或catch 处理前拦截他们
    // 添加请求拦截器
    axios.interceptors.request.use(function (config) {
        // 在发送请求之前做些什么
        return config;
      }, function (error) {
        // 对请求错误做些什么
        return Promise.reject(error);
      });
    
    // 添加响应拦截器
    axios.interceptors.response.use(function (response) {
        // 对响应数据做点什么
        return response;
      }, function (error) {
        // 对响应错误做点什么
        return Promise.reject(error);
      });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    源码
    在这里插入图片描述

    1. 移除拦截器
    const myInterceptor = axios.interceptors.request.use(function () {/*...*/});
    axios.interceptors.request.eject(myInterceptor);
    
    • 1
    • 2

    源码:
    在这里插入图片描述

    2.2.5 转换请求数据和响应数据
    1. 转换请求数据,在请求拦截里面处理
      请求数据就是参数config
      比较常见的处理就是在这里给所有请求都加上TOKEN
    axios.interceptors.request.use(function (config) {
        config.headers["Authorization"] = "Bearer " + Cookies.get(TOKEN_KEY);
        return config;
      }, function (error) {
        // 对请求错误做些什么
        return Promise.reject(error);
      });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    1. 相对应的转换相应数据,就是在响应拦截里面处理
      相应数据就是参数response
      这里通常用来处理状态码 以及 用户权限不够时的画面或者是回应
    // 添加响应拦截器
    axios.interceptors.response.use(function (response) {
        // 对响应数据做点什么
        //200 正常  
        return response;
      }, function (error) {
        // 对响应错误做点什么
        return Promise.reject(error);
      });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    2.2.6 取消请求

    使用 cancel token 取消请求

    Axioscancel token API 基于cancelable promises proposal,它还处于第一阶段。

    • 可以使用 CancelToken.source 工厂方法创建 cancel token
    • 可以使用同一个 cancel token 取消多个请求
    const CancelToken = axios.CancelToken;
    const source = CancelToken.source();
    
    axios.get('/user/12345', {
      cancelToken: source.token
    }).catch(function(thrown) {
      if (axios.isCancel(thrown)) {
        console.log('Request canceled', thrown.message);
      } else {
         // 处理错误
      }
    });
    
    axios.post('/user/12345', {
      name: 'new name'
    }, {
      cancelToken: source.token
    })
    
    // 取消请求(message 参数是可选的)
    source.cancel('Operation canceled by the user.');
    还可以通过传递一个 executor 函数到 CancelToken 的构造函数来创建 cancel token:
    
    const CancelToken = axios.CancelToken;
    let cancel;
    
    axios.get('/user/12345', {
      cancelToken: new CancelToken(function executor(c) {
        // executor 函数接收一个 cancel 函数作为参数
        cancel = c;
      })
    });
    
    // cancel the request
    cancel();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    源码:可以看出也跟Promise脱不了干系
    在这里插入图片描述

    2.2.7 自动转换 JSON 数据

    当你使用 Axios 发送请求时,如果响应的内容类型是 application/json,Axios 会自动解析 JSON 数据。你不需要手动进行转换。
    在这里插入图片描述

    2.2.8 客户端支持防御 XSRF

    关于XSRF下面 3.1 里面有具体一些的解释

    Axios防御XSRF主要是通过 CSRF 令牌 来 预防

    使用
    1. 确保服务器发送一个名为XSRF-TOKENcookie
    2. 确保axios请求头包含这个cookie
    const axios = require('axios');
    
    // 创建一个axios实例
    const instance = axios.create({
      baseURL: 'http://example.com/api', 
      withCredentials: true, // 允许axios发送cookie
      xsrfCookieName: 'XSRF-TOKEN', // 默认为'XSRF-TOKEN',如果服务器使用不同的名称,需要修改
      xsrfHeaderName: 'X-XSRF-TOKEN', // 默认为'X-XSRF-TOKEN',如果服务器使用不同的头部字段名称,需要修改
    });
     
    // 使用实例发送请求
    instance.get('/someEndpoint')
      .then(response => {
        // 处理响应
        console.log(response.data);
      })
      .catch(error => {
        // 处理错误
        console.error(error);
      });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    withCredentials: true选项允许axios在跨域请求中发送cookies
    xsrfCookieNamexsrfHeaderName选项确保axios知道如何读取和发送正确的XSRF令牌

    需要注意的是:

    1. 服务器必须正确配置以发送XSRF令牌cookie
    2. 客户端必须在请求中包含这个cookie
    源码如下:

    在这里插入图片描述
    在这里插入图片描述

    2.3 请求配置

    以下是创建请求时可以用的配置选项。

    • 只有 url 是必需的。
    • 如果没有指定 method,请求将默认使用get方法。
    {
       // `url` 是用于请求的服务器 URL
      url: '/user',
    
      // `method` 是创建请求时使用的方法
      method: 'get', // default
    
      // `baseURL` 将自动加在 `url` 前面,除非 `url` 是一个绝对 URL。
      // 它可以通过设置一个 `baseURL` 便于为 axios 实例的方法传递相对 URL
      baseURL: 'https://some-domain.com/api/',
    
      // `transformRequest` 允许在向服务器发送前,修改请求数据
      // 只能用在 'PUT', 'POST' 和 'PATCH' 这几个请求方法
      // 后面数组中的函数必须返回一个字符串,或 ArrayBuffer,或 Stream
      transformRequest: [function (data, headers) {
        // 对 data 进行任意转换处理
        return data;
      }],
    
      // `transformResponse` 在传递给 then/catch 前,允许修改响应数据
      transformResponse: [function (data) {
        // 对 data 进行任意转换处理
        return data;
      }],
    
      // `headers` 是即将被发送的自定义请求头
      headers: {'X-Requested-With': 'XMLHttpRequest'},
    
      // `params` 是即将与请求一起发送的 URL 参数
      // 必须是一个无格式对象(plain object)或 URLSearchParams 对象
      params: {
        ID: 12345
      },
    
       // `paramsSerializer` 是一个负责 `params` 序列化的函数
      // (e.g. https://www.npmjs.com/package/qs, http://api.jquery.com/jquery.param/)
      paramsSerializer: function(params) {
        return Qs.stringify(params, {arrayFormat: 'brackets'})
      },
    
      // `data` 是作为请求主体被发送的数据
      // 只适用于这些请求方法 'PUT', 'POST', 和 'PATCH'
      // 在没有设置 `transformRequest` 时,必须是以下类型之一:
      // - string, plain object, ArrayBuffer, ArrayBufferView, URLSearchParams
      // - 浏览器专属:FormData, File, Blob
      // - Node 专属: Stream
      data: {
        firstName: 'Fred'
      },
    
      // `timeout` 指定请求超时的毫秒数(0 表示无超时时间)
      // 如果请求话费了超过 `timeout` 的时间,请求将被中断
      timeout: 1000,
    
       // `withCredentials` 表示跨域请求时是否需要使用凭证
      withCredentials: false, // default
    
      // `adapter` 允许自定义处理请求,以使测试更轻松
      // 返回一个 promise 并应用一个有效的响应 (查阅 [response docs](#response-api)).
      adapter: function (config) {
        /* ... */
      },
    
     // `auth` 表示应该使用 HTTP 基础验证,并提供凭据
      // 这将设置一个 `Authorization` 头,覆写掉现有的任意使用 `headers` 设置的自定义 `Authorization`头
      auth: {
        username: 'janedoe',
        password: 's00pers3cret'
      },
    
       // `responseType` 表示服务器响应的数据类型,可以是 'arraybuffer', 'blob', 'document', 'json', 'text', 'stream'
      responseType: 'json', // default
    
      // `responseEncoding` indicates encoding to use for decoding responses
      // Note: Ignored for `responseType` of 'stream' or client-side requests
      responseEncoding: 'utf8', // default
    
       // `xsrfCookieName` 是用作 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` 允许为上传处理进度事件
      onUploadProgress: function (progressEvent) {
        // Do whatever you want with the native progress event
      },
    
      // `onDownloadProgress` 允许为下载处理进度事件
      onDownloadProgress: function (progressEvent) {
        // 对原生进度事件的处理
      },
    
       // `maxContentLength` 定义允许的响应内容的最大尺寸
      maxContentLength: 2000,
    
      // `validateStatus` 定义对于给定的HTTP 响应状态码是 resolve 或 reject  promise 。如果 `validateStatus` 返回 `true` (或者设置为 `null` 或 `undefined`),promise 将被 resolve; 否则,promise 将被 rejecte
      validateStatus: function (status) {
        return status >= 200 && status < 300; // default
      },
    
      // `maxRedirects` 定义在 node.js 中 follow 的最大重定向数目
      // 如果设置为0,将不会 follow 任何重定向
      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.
      socketPath: null, // default
    
      // `httpAgent` 和 `httpsAgent` 分别在 node.js 中用于定义在执行 http 和 https 时使用的自定义代理。允许像这样配置选项:
      // `keepAlive` 默认没有启用
      httpAgent: new http.Agent({ keepAlive: true }),
      httpsAgent: new https.Agent({ keepAlive: true }),
    
      // 'proxy' 定义代理服务器的主机名称和端口
      // `auth` 表示 HTTP 基础验证应当用于连接代理,并提供凭据
      // 这将会设置一个 `Proxy-Authorization` 头,覆写掉已有的通过使用 `header` 设置的自定义 `Proxy-Authorization` 头。
      proxy: {
        host: '127.0.0.1',
        port: 9000,
        auth: {
          username: 'mikeymike',
          password: 'rapunz3l'
        }
      },
    
      // `cancelToken` 指定用于取消请求的 cancel token
      // (查看后面的 Cancellation 这节了解更多)
      cancelToken: new CancelToken(function (cancel) {
      })
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133

    2.4 使用

    2.4.1 安装

    三种方法 很常见的

    1. 使用 npm:
    npm install axios
    
    • 1
    1. 使用 bower:
    bower install axios
    
    • 1
    1. 使用 cdn:
    <script src="https://unpkg.com/axios/dist/axios.min.js">script>
    
    • 1
    2.4.2 axios 模块化

    首先要知道什么是模块化,在前端代码里面来说就是。
    根据某一规则来将代码划分到不同文件夹下。
    一般情况下是根据模型-数据-对接这种来写

    如果你想要实现axios 模块化 以及简易写法 必须学会模块化

    1. 首先 在src目录下面新建一个文件夹叫 “api”
      在这里插入图片描述
    2. 接下来新建index.js 主要做axios的请求响应或者请求拦截
      在index中开始写配置基础文件
      import axios from 'axios'
    
      import {bus} from '../bus.js'
    
    • 1
    • 2
    • 3
    1. 这里的bus文件其实是与main.js 同级
      目的是为了能够在执行接下来返回,一但请求不到数据 就让他返回登录页面重新登录
      bus.js 文件如下 :
      import Vue from 'vue'
      export let bus = new Vue()
    
    • 1
    • 2
    1. 而这个bus文件得在我写的那个项目下面的Home页面Home是切换所有页面的根页面)中用
      注意要写在created生命周期中
      import {bus} from '../bus.js'
      created(){
          bus.$on('goto', (url) => {
            if (url === "/login") {
              localStorage.removeItem('access-user');
            }
            this.$router.push(url);
          })
        },
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    1. 接下来配置基础路径:
      这一步主要是配置请求的地址,省略在开发中配置大量的地址
      axios.defaults.baseURL = 'https://api.example.com';
    
    • 1

    接下来是拦截器部分

    //添加一个请求拦截器
     axios.interceptors.request.use(function (config) {
       console.dir(config);
       return config;
     }, function (error) {
       // Do something with request error
       return Promise.reject(error);
     });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    实际开发中请求响应以及请求拦截都会用到,这里我们说请求响应拦截

    // 添加一个响应拦截器
    axios.interceptors.response.use(function (response) {
      if (response.data && response.data.errcode) {
        if (parseInt(response.data.errcode) === 40001) {
          //未登录
          bus.$emit('goto', '/login')
        }
      }
    
      return response;
    }, function (error) {
      // Do something with response error
      return Promise.reject(error);
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    如果不满足请求的条件
    response.data下面会有 errcode 这么一个值 他的值为 40001 代表返回响应出错
    需要重新查找自己能够返回响应的条件

    接口代理地址有以下三种方式:

    1. 用( axios.defaults.baseURL)直接配置 上面我有提到
    2. config/index.js中的proxyTable配置,
      配置代码如下
       dev: {
         env: require('./dev.env'),
         port: 4000,
         autoOpenBrowser: true,
         assetsSubDirectory: 'static',
         assetsPublicPath: '/',
         proxyTable: {
           '/api': {
             changeOrigin: true,
             target: 'https://api.example.com',
             pathRewrite: {
               '^/api': ''
             }
           }
         },
       }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    1. 自定义一个基地址
      let base = 'https://api.example.com'; 
    
    • 1
    通用代码
    1. 第一种配置方式书写 通用代码:
    //通用方法
    export const POST = (url, params) => {
      return axios.post(`${url}`, params).then(res => res.data)
    }
    
    export const GET = (url, params) => {
      return axios.get(`${url}`,{params: params}).then(res => res.data)
    }
    
    export const PUT = (url, params) => {
      return axios.put(`${url}`, params).then(res => res.data)
    }
    
    export const DELETE = (url, params) => {
      return axios.delete(`${url}`, {params: params}).then(res => res.data)
    }
    
    export const PATCH = (url, params) => {
      return axios.patch(`${url}`, params).then(res => res.data)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    1. 第二种配置方式通用代码:
    export const POST = (url, params) => {
      return axios.post(`api${url}`, params).then(res => res.data)
    }
    
    export const GET = (url, params) => {
      return axios.get(`api${url}`, {params: params}).then(res => res.data)
    }
    
    export const PUT = (url, params) => {
      return axios.put(`api${url}`, params).then(res => res.data)
    }
    
    export const DELETE = (url, params) => {
      return axios.delete(`api${url}`, {params: params}).then(res => res.data)
    }
    
    export const PATCH = (url, params) => {
      return axios.patch(`api${url}`, params).then(res => res.data)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    1. 第三种书写方式通用代码:
    //通用方法
    export const POST = (url, params) => {
      return axios.post(`${base}${url}`, params).then(res => res.data)
    }
    
    export const GET = (url, params) => {
      return axios.get(`${base}${url}`, {params: params}).then(res => res.data)
    }
    
    export const PUT = (url, params) => {
      return axios.put(`${base}${url}`, params).then(res => res.data)
    }
    
    export const DELETE = (url, params) => {
      return axios.delete(`${base}${url}`, {params: params}).then(res => res.data)
    }
    
    export const PATCH = (url, params) => {
      return axios.patch(`${base}${url}`, params).then(res => res.data)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    接下来得做一件事 在api这个文件夹下重新在写一个js 我这里叫api.js
    在这里调用 index.js 在这里写定义的调用方法:
    内容如下

    import * as API from './'
    
    export default {
    add: params => {
      return API.GET('/api/pol/web/live/add', params)
    },
    detail: params => {
      return API.POST('/api/pol/web/live/detail', params)
    },
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    ps:这个add 和detail 我只是写了个示例 实际情况根据实际的来

    最后就是在每个页面中调用了

    内容如下

    import qs  from "qs"
    这里的qs 是一个增加了一些安全性的查询字符串解析和序列化字符串的库。
    
    import API from '../api/api.js';
    
    API.add(qs.stringify({这里写你要传的键值对})).then((res)=>{
        //成功之后回调
    }).catch((err)=>{
        //失败之后回调
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    这是针对整个axios封装或者说是模块化的过程

    3. 扩充

    3.1 跨站请求伪造(CSRF

    3.1.1 定义

    CSRF(有时也称为 XSRF)是一类相关的攻击。攻击者使用户的浏览器在用户不知情的情况下向网站的后端发送请求。攻击者可以使用 XSS 载荷发起 CSRF 攻击。

    3.1.2 示例

    维基百科提到了一个很好的CSRF示例。
    在这种情况下,某人访问了一个实际上并不是图像的图像
    (例如在未经过滤的聊天或论坛中),而是向银行服务器发出取款请求:

    <img
      src="https://bank.example.com/withdraw?account=bob&amount=1000000&for=mallory" />
    
    • 1
    • 2

    现在如果你登录银行账户并且你的 cookie 仍然有效(并且没有其他验证),那么在加载包含此图像的HTML后你将立即转账。对于需要 POST 请求的端点,可以在加载页面时以编程方式触发

    提交(可能在不可见的