网络请求

前端网络请求方式

  1. Ajax 是 Asynchronous JavaScript and XML(异步的 JavaScript 与 XML 技术)的缩写
  2. JQuery ajax 是对原生 XHR 的封装,除此以外还增添了对 JSONP 的支持
  3. fetch 是原生 js 中 Ajax 的替代者,没有使用 XMLHttpRequest 对象,但本身也是原生 js
  4. axios、request 开源库

Ajax

同步请求:等待数据加载完成出现页面,先加载数据后进行页面数据展示 异步请求:局部刷新页面,边请求,边展示,利于提高用户体验

1.隐藏帧 iframe

隐藏帧实现局部更新,实际上 iframe 就相当于页面的子页面

<div>
  <form action="./iframe.php" method="POST" target="myframe">
    账号:<input type="text" name="username" /><span id="info"></span><br />
    密码:<input type="password" name="password" /><br />
    <input type="submit" value="登录" />
  </form>
</div>
<iframe width="0" height="0" frameborder="0" name="myframe"></iframe>

2.Ajax 实现页面的局部刷新

使用 Ajax 发送请求需要如下几步:

  1. 创建 XMLHttpRequest 对象
  2. 准备发送
  3. 执行发送动作
  4. 指定回调函数
<form action="">
  账号:<input type="text" name="username" id="username" /><br />
  密码:<input type="password" name="password" id="password" />
  <input type="button" value="提交" id="btn" />
</form>
window.onload = function () {
  var btn = document.getElementById('btn')
  btn.onclick = function () {
    var uname = document.getElementById('username').value
    var pw = document.getElementById('password').value
    //1.创建XMLHttpRequest对象
    var xhr = new XMLHttpRequest()
    //2.准备发送
    xhr.open('get', './01check.php?username=' + uname + '&password' + pw, true)
    //3.执行发送动作
    xhr.send(null)
    //4.指定回调函数
    xhr.onreadystatechange = function () {
      if (xhr.readyState == 4) {
        if (xhr.status == 200) {
          var data = xhr.responseText
          var info = document.getElementById('info')
          if (data == '1') {
            info.innerHTML = '登录成功'
          } else if (data == '2') {
            info.innerHTML = '用户名或密码错误'
          }
        }
      }
    }
  }
}

3.xhr 对象创建

标准浏览器:var xhr = new XMLHttpRequest(); IE6 老版本:var xhr = new ActiveXObject("Microsoft.XMLHTTP"); xhr 兼容性处理:

var xhr = null
if (window.XMLHttpRequest) {
  xhr = new XMLHttpRequest() //标准
} else {
  xhr = new new ActiveXObject('Microsoft.XMLHTTP')() //IE6
}

4.GET 请求

<form action="">
  用户名:<input type="text" id="username" name="username" />
  <span id="info"></span> <br />
  密码:<input type="password" name="password" id="password" />
  <input type="button" value="登录" id="btn" />
</form>
window.onload = function () {
  var btn = document.getElementById('btn')
  btn.onclick = function () {
    var uname = document.getElementById('username').value
    var pw = document.getElementById('password').value
    //1.创建创建XMLHttpRequest对象
    //处理兼容性
    var xhr = null
    if (window.XMLHttpRequest) {
      xhr = new XMLHttpRequest() //标准
    } else {
      xhr = new ActiveXObject('Microsoft.XMLHTTP') //IE6
    }
    //2.准备发送
    /*
            参数1:请求方式(get获取数据,post提交数据)
            参数2:请求地址
            参数3:同步或者异步标志位,默认是true表示异步,false表示同步

            如果是get 请求那么请求参数必须是在url中传递
            encodeURI() 用来对中文参数进行编码,防止出现乱码
        */
    var param = 'username=' + uname + '&password=' + pw
    xhr.open('get', '04get.php?' + encodeURI(param), true)
    //3.发送请求,执行发送动作
    xhr.send(null) // get请求这里需要添加 null 参数
    //4.指定回调函数
    xhr.onreadystatechange = function () {
      if (xhr.readyState == 4) {
        if (xhr.status == 200) {
          alert(xhr.responseText)
        }
      }
    }
  }
}

5.POST 请求

<form action="">
  用户名:<input type="text" id="username" name="username" />
  <span id="info"></span> <br />
  密码:<input type="password" name="password" id="password" />
  <input type="button" value="登录" id="btn" />
</form>
window.onload = function () {
  var btn = document.getElementById('btn')
  btn.onclick = function () {
    var uname = document.getElementById('username').value
    var pw = document.getElementById('password').value
    //1.创建创建XMLHttpRequest对象
    //处理兼容性
    var xhr = null
    if (window.XMLHttpRequest) {
      xhr = new XMLHttpRequest() //标准
    } else {
      xhr = new new ActiveXObject('Microsoft.XMLHTTP')() //IE6
    }
    //2.准备发送
    /*
        参数1:请求方式(get获取数据,post提交数据)
        参数2:请求地址
        参数3:同步或者异步标志位,默认是true表示异步,false表示同步

        post请求参数通过send传递,不需要通过encodeURI()转码啊
        必须设置请求头信息
        */
    var param = 'username=' + uname + '&password=' + pw
    xhr.open('post', '05post.php', true)
    //3.发送请求,执行发送动作
    xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
    xhr.send(param) // post请求参数在这传递,并且不炫耀转码
    //4.指定回调函数
    xhr.onreadystatechange = function () {
      if (xhr.readyState == 4) {
        if (xhr.status == 200) {
          alert(xhr.responseText)
        }
      }
    }
  }
}

6.相应状态分析

window.onload = function () {
  var btn = document.getElementById('btn')
  btn.onclick = function () {
    var uname = document.getElementById('username').value
    var pw = document.getElementById('password').value
    //1.创建创建XMLHttpRequest对象
    //处理兼容性
    var xhr = null
    if (window.XMLHttpRequest) {
      xhr = new XMLHttpRequest() //标准
    } else {
      xhr = new new ActiveXObject('Microsoft.XMLHTTP')() //IE6
    }
    //readyState = 0 表示xhr 对象创建完成
    console.log(xhr.readyState + '————————1————————')
    //2.准备发送
    /*
        参数1:请求方式(get获取数据,post提交数据)
        参数2:请求地址
        参数3:同步或者异步标志位,默认是true表示异步,false表示同步

        如果是get 请求那么请求参数必须是在url中传递
        encodeURI() 用来对中文参数进行编码,防止出现乱码
        */
    var param = 'username=' + uname + '&password=' + pw
    xhr.open('get', '06.php?' + encodeURI(param), true)
    //3.发送请求,执行发送动作
    xhr.send(null) // get请求这里需要添加 null 参数
    //4.指定回调函数
    //readyState = 1 表示已经发送了请求
    console.log(xhr.readyState + '————————2————————')
    //该函数调用的条件激素hireadyState状态发生变化(不包括从0变为1)
    xhr.onreadystatechange = function () {
      /*
        readyState:
        2 表示了已经接收到了服务器相应的数据
        3 表示正在解析数据
        4 表示数据已经解析完成, 可以使用了
        */
      console.log(xhr.readyState + '————————3————————')
      /*
        http的常见状态码:
        200 表示相应成功
        404 表示没有找到请求的资源
        500 表示服务器端错误
        */

      //4 表示服务器端返回的数据已经可以使用了,但是这个数据不一定是正常的
      //200 表示服务器返回的数据是正常的 ,不是200表示数据是错误的
      if (xhr.readyState == 4) {
        if (xhr.status == 200) {
          alert(xhr.responseText)
          //xhr.responseXML
        }
      }
    }
  }
}

7.回调函数

  • onreadysatechange
  • xhr.readyState
    • 0 xhr 对象初始化
    • 1 执行发送动作
    • 2 服务器端数据已经完全返回
    • 3 数据正在解析
    • 4 数据解析完成,可以使用
  • xhr.status
    • 200 数据相应正常
    • 404 没有找到资源
    • 500 服务器端错误

8.xml 数据格式

  • 元数据:描述有效数据的数据
  • 这种数据格式的弊端
    • 元数据占用数据量比较大,不利于大量数据的网络传输
    • 解析不太方便
window.onload = function () {
  var btn = document.getElementById('btn')
  btn.onclick = function () {
    var uname = document.getElementById('username').value
    var pw = document.getElementById('password').value

    // 1、创建XMLHttpRequest对象
    var xhr = null
    if (window.XMLHttpRequest) {
      xhr = new XMLHttpRequest() //标准
    } else {
      xhr = new ActiveXObject('Microsoft') //IE6
    }
    // readyState=0表示xhr对象创建完成
    // 2、准备发送
    var param = 'username=' + uname + '&password=' + pw
    // xhr.open('post','data.xml',true);
    xhr.open('post', '09.php', true)
    // 3、执行发送动作
    xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
    xhr.send(param) //post请求参数在这里传递,并且不需要转码
    // 4、指定回调函数
    // 该函数调用的条件就是readyState状态发生变化(不包括从0变为1)
    xhr.onreadystatechange = function () {
      if (xhr.readyState == 4) {
        if (xhr.status == 200) {
          var data = xhr.responseXML
          var bookList = data.getElementsByTagName('booklist')
          var books = bookList[0].children
          var book1 = books[0]

          var name = book1.children[0].firstChild.wholeText
          var author = book1.children[1].firstChild.wholeText
          var desc = book1.children[2].firstChild.wholeText
          console.log(name, author, desc)
        }
      }
    }
  }
}

9.json 数据格式(对象)

json 数据和普通的 js 对象的区别

  1. json 数据没有变量
  2. json 形式的书结尾没有分号
  3. json 数据中的键必须用双引号包住
var str = { name: 'zhangsan', age: 12 }
var obj = JSON.parse(str) //把json形式的字符串转换成对象
console.log(obj)

var str1 = JSON.stringify(obj) //把对象转换成字符串
console.log(str1) //{"name":"zhangsan", "age":12}

window.onload = function () {
  var btn = document.getElementById('btn')
  btn.onclick = function () {
    var username = document.getElementById('username')
    var password = document.getElementById('password')
    //1.创建创建XMLHttpRequest对象
    var xhr = null
    if (window.XMLHttpRequest) {
      xhr = new XMLHttpRequest() //常规浏览器
    } else {
      xhr = new ActiveXObject('Microsoft') //IE6
    }
    //2.准备发送
    var param = 'username' + username + '&password' + password
    xhr.open('get', '010.json?' + encodeURI(param), true)
    //3.发送请求
    xhr.send(null) //get请求需要在这添加null
    //4.回调函数
    xhr.onreadystatechange = function () {
      if (xhr.readyState == 4) {
        if (xhr.status == 200) {
          var data = xhr.responseText
          //var d = eval("("+ data +")"); //eval() 的作用就是把字符串解析成js代码并执行
          var d = JSON.parse(data)
          console.log(d.name)
          console.log(d.age)
          console.log(d.friend.hig)
          console.log(d.friend.wight)
          console.log(d.friend.lover)
        }
      }
    }
  }
}

10.异步请求与同步请求的理解

  • 同步加载页面整个重新加载--w3school.org
  • 异步加载页面局部加载--评论加载

描述两者之间的行为方式

  1. 同步 彼此等待 ---- 阻塞
  2. 异步 各做各的 ---- 非阻塞

11.同步请求与异步请求底层原理分析

/*
异步效果与js事件处理机制
定时函数
    setTimeout()
    setInterval()

事件函数
    btn.onclick = function () {

    }

Ajax 回调行数
    xhr.onreadystatechange = function () {

    }
*/
/*
js运行机制
    单线程 + 事件队列

    事件队列中的任务执行的条件
        1.主线程已经空闲
        2.任务满足触发条件
            a.定时函数(延时时间已经到达)
            b.事件函数(特定事件被触发)
            c.Ajax 的回调函数(服务端有数据相应)
*/

//定时任务(函数)
console.log(1)
setTimeout(function () {
  console.log(2)
}, 0)
var sum = 0
for (var i = 0; i < 10000; i++) {
  sum += i
}
console.log(sum)
console.log(3)

//事件函数
window.onload = function () {
  var btn = document.getElementById('btn')
  console.log('事件函数1')
  btn.onclick = function () {
    console.log(this.value)
  }
  console.log('事件函数2')
}

//ajax 回调函数
window.onload = function () {
  var btn = document.getElementById('btn')
  btn.onclick = function () {
    //1.创建XMLHttpRequest对象
    var xhr = null
    if (window.XMLHttpRequest) {
      xhr = new XMLHttpRequest() //标准
    } else {
      xhr = new ActiveXObject('Microsoft.XMLHTTP') //IE6
    }
    //2.准备发送
    xhr.open('get', '013.php')
    //3.发送请求
    xhr.send(null)
    console.log('11')
    //4.指定回调行数
    xhr.onreadystatechange = function () {
      if (xhr.readyState == 4) {
        if (xhr.status == 200) {
          var data = xhr.responseText
          var obj = JSON.parse(data)
          var tag =
            '<div><span>' +
            obj.info +
            '</span><span>-----</span><span>' +
            obj.message +
            '</span></div>'
          var info = document.getElementById('info')
          info.innerHTML = tag
          console.log('22')
        }
      }
    }
    console.log('33')
  }
}

jQueryAjax

jQueryAjax 和原生 Ajax 比较

  1. 传统 Ajax 指的是 XMLHttpRequest(XHR), 最早出现的发送后端请求技术,隶属于原始 js 中,核心使用 XMLHttpRequest 对象,多个请求之间如果有先后关系的话,就会出现回调地狱。

  2. JQuery ajax 是对原生 XHR 的封装,除此以外还增添了对 JSONP 的支持。经过多年的更新维护,真的已经是非常的方便了,优点无需多言;如果是硬要举出几个缺点,那可能只有:

    • 本身是针对 MVC 的编程,不符合现在前端 MVVM 的浪潮
    • 基于原生的 XHR 开发,XHR 本身的架构不清晰。
    • JQuery 整个项目太大,单纯使用 ajax 却要引入整个 JQuery 非常的不合理(采取个性化打包的方案又不能享受 CDN 服务)
    • 不符合关注分离(Separation of Concerns)的原则
    • 配置和调用方式非常混乱,而且基于事件的异步模型不友好

TIP

  • MVVM(Model-View-ViewModel), 源自于经典的 Model–View–Controller(MVC)模式。
  • MVVM 的出现促进了 GUI 前端开发与后端业务逻辑的分离,极大地提高了前端开发效率。
  • MVVM 的核心是 ViewModel 层,它就像是一个中转站(value converter),负责转换 Model 中的数据对象来让数据变得更容易管理和使用,该层向上与视图层进行双向数据绑定,向下与 Model 层通过接口请求进行数据交互,起呈上启下作用。
  • View 层展现的不是 Model 层的数据,而是 ViewModel 的数据,由 ViewModel 负责与 Model 层交互,这就完全解耦了 View 层和 Model 层,这个解耦是至关重要的,它是前后端分离方案实施的最重要一环

jQueryAjax 封装

function ajax(obj) {
  //默认参数
  var defaults = {
    type: 'get',
    data: {},
    url: '#',
    dataType: 'text',
    async: true,
    success: function (data) {
      console.log(data)
    }
  }
  //处理形参,传递参数的时候就覆盖默认参数,不传递就使用默认参数
  for (var key in obj) {
    defaults[key] = obj[key]
  }
  //1.设置XMLHttpRequest对象
  var xhr = null
  if (window.XMLHttpRequest) {
    xhr = new XMLHttpRequest()
  } else {
    xhr = new ActiveXObject('Microsoft.XMLHTTP')
  }
  //把对象形式的参数,转换为字符串形式的参数
  /*
    {username:'张三',password:'123'}
    转换为
    username=张三&password=132
    */
  var param = ''
  for (var attr in obj.data) {
    param += attr + '=' + obj.data[attr] + '&'
  }
  if (param) {
    param = param.substring(0, param.length - 1)
  }
  //处理get请求参数并且处理中文乱码问题
  if (defaults.type == 'get') {
    defaults.url += '?' + encodeURI(param)
  }
  //2.准备发送(设置发送的参数)
  xhr.open(defaults.type, defaults.url, defaults.async)
  //处理post请求参数并且设置请求头信息(必须设置)
  var data = null
  if (defaults.type == 'post') {
    data = param
    xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
  }
  //3.执行发送请求
  xhr.send(data)
  //处理同步请求:不会调用回调函数
  if (defaults.async) {
    if (defaults.dataType == 'json') {
      return JSON.parse(xhr.responseText)
    } else {
      return xhr.responseText
    }
  }
  //执行回调函数(异步请求调用)
  xhr.onreadystatechange = function () {
    if (xhr.readyState == 4) {
      if (xhr.status == 200) {
        var data = xhr.responseText
        if (defaults.dataType == 'json') {
          data = JSON.parse(data) //转换成json
          //data = eval("("+ data +")");
        }
        defaults.success(data)
      }
    }
  }
}

fetch

fetch 号称是 AJAX 的替代品,是在 ES6 出现的,使用了 ES6 中的 promise 对象。Fetch 是基于 promise 设计的。Fetch 的代码结构比起 ajax 简单多了,参数有点像 jQuery ajax。但是,一定记住 fetch 不是 ajax 的进一步封装,而是原生 js,没有使用 XMLHttpRequest 对象。

fetch 的优点

  1. 符合关注分离,没有将输入、输出和用事件来跟踪的状态混杂在一个对象里
  2. 更好更方便的写法(语法简洁,更加语义化)
  3. 基于标准 Promise 实现,支持 async/await
  4. 同构方便,使用 isomorphic-fetchopen in new window
  5. 更加底层,提供的 API 丰富(request, response)
  6. 脱离了 XHR,是 ES 规范里新的实现方式

fetch 基本用法

GET

fetch('/test/content.json')
  .then(function (data) {
    return data.json()
  })
  .then(function (data) {
    console.log('data :>> ', data)
  })
  .catch(function (error) {
    console.log('error :>> ', error)
  })

POST

fetch('/test/content.json', {
  // url: fetch事实标准中可以通过Request相关api进行设置
  method: 'POST',
  mode: 'same-origin', // same-origin|no-cors(默认)|cors
  credentials: 'include', // omit(默认,不带cookie)|same-origin(同源带cookie)|include(总是带cookie)
  headers: {
    // headers: fetch事实标准中可以通过Header相关api进行设置
    'Content-Type': 'application/x-www-form-urlencoded' // default: 'application/json'
  },
  body: 'a=1&b=2' // body: fetch事实标准中可以通过Body相关api进行设置
})
  .then(function (res) {
    res: fetch事实标准中可以通过Response相关api进行设置
    return res.json()
  })
  .then(function (data) {
    console.log(data)
  })
  .catch(function (error) {})

Response 相关属性及方法

bodyUsed

  • 标记返回值是否被使用过
  • 这样设计的目的是为了之后兼容基于流的 API,让应用一次消费 data,这样就允许了 JavaScript 处理大文件例如视频,并且可以支持实时压缩和编辑
fetch('/test/content.json')
  .then(function (res) {
    console.log(res.bodyUsed) // false
    var data = res.json()
    console.log(res.bodyUsed) //true
    return data
  })
  .then(function (data) {
    console.log(data)
  })
  .catch(function (error) {
    console.log(error)
  })

headers

返回 Headers 对象,该对象实现了 Iterator,可通过 for...of 遍历

fetch('/test/content.json')
  .then(function (res) {
    var headers = res.headers
    console.log(headers.get('Content-Type')) // application/json
    console.log(headers.has('Content-Type')) // true
    console.log(headers.getAll('Content-Type')) // ["application/json"]
    for (let key of headers.keys()) {
      console.log(key) // datelast-modified server accept-ranges etag content-length content-type
    }
    for (let value of headers.values()) {
      console.log(value)
    }
    headers.forEach(function (value, key, arr) {
      console.log(value) // 对应values()的返回值
      console.log(key) // 对应keys()的返回值
    })
    return res.json()
  })
  .then(function (data) {
    console.log(data)
  })
  .catch(function (error) {
    console.log(error)
  })

ok

  • 是否正常返回
  • 代表状态码在 200~299 之间

status

  • 状态码
    • 200 成功
    • 500 服务器错误

statusText

  • 状态描述
    • ok 成功
    • clone 取消

type

  • basic:正常的,同域的请求,包含所有的 headers。排除 Set-Cookie 和 Set-Cookie2
  • cors:Response 从一个合法的跨域请求获得,一部分 header 和 body 可读
  • error:网络错误。Response 的 status 是 0,Headers 是空的并且不可写。当 Response 是从 Response.error()中得到时,就是这种类型
  • opaque: Response 从"no-cors"请求了跨域资源。依靠 Server 端来做限制

url

返回完整的 url 字符串。如:'http://xxx.com/xx?a=1'

arrayBuffer()

返回 ArrayBuffer 类型的数据的 Promise 对象

blob()

返回 Blob 类型的数据的 Promise 对象

clone()

  • 生成一个 Response 的克隆
  • body 只能被读取一次,但 clone 方法就可以得到 body 的一个备份
  • 克隆体仍然具有 bodyUsed 属性,如果被使用过一次,依然会失效
fetch('/test/content.json')
  .then(function (data) {
    var d = data.clone()
    d.text().then(function (text) {
      console.log(JSON.parse(text))
    })
    return data.json()
  })
  .then(function (data) {
    console.log(data)
  })
  .catch(function (error) {
    console.log(error)
  })

json()

返回 JSON 类型的数据的 Promise 对象

text()

返回 Text 类型的数据的 Promise 对象

formData()

返回 FormData 类型的数据的 Promise 对象

缺陷

  • 无法监控读取进度
  • 无法中断请求

fetch 使用遇到的问题

  1. fetch 只对网络请求报错,对 400,500 都当做成功的请求,服务器返回 400,500 错误码时并不会 reject,只有网络错误这些导致请求不能完成时,fetch 才会被 reject。
  2. fetch 默认不会带 cookie,需要添加配置项: fetch(url, {credentials: 'include'})
  3. fetch 不支持 abort,不支持超时控制,使用 setTimeout 及 Promise.reject 的实现的超时控制并不能阻止请求过程继续在后台运行,造成了流量的浪费
  4. fetch 没有办法原生监测请求的进度,而 XHR 可以

axios

axios 是一个基于 Promise 用于浏览器和 nodejs 的 HTTP 客户端,本质上也是对原生 XHR 的封装,只不过它是 Promise 的实现版本,符合最新的 ES 规范,它本身具有以下特征:

  1. 从浏览器中创建 XMLHttpRequest
  2. 支持 Promise API
  3. 客户端支持防止 CSRF
  4. 提供了一些并发请求的接口(重要,方便了很多的操作)
  5. 从 node.js 创建 http 请求
  6. 拦截请求和响应
  7. 转换请求和响应数据
  8. 取消请求
  9. 自动转换 JSON 数据

TIP

防止 CSRF:就是让你的每个请求都带一个从 cookie 中拿到的 key, 根据浏览器同源策略,假冒的网站是拿不到你 cookie 中得 key 的,这样,后台就可以轻松辨别出这个请求是否是用户在假冒网站上的误导输入,从而采取正确的策略。

axios 安装

yarn add axios

请求拦截

注意:涉及到 token 的存储、vuex 存储 token 在对应的章节进行描述。request.ts文件只是使用 在项目src文件夹下创建文件夹 utils文件夹 ,并创建 request.ts 文件,文件内容如下:

import axios, { AxiosResponse, AxiosRequestConfig } from 'axios'
import { notification } from 'ant-design-vue' // 结合 ant-design-vue 做全局提示
import store from '@/store' // 获取 token
import { localCache } from '@/utils/storage' // 引入读取token
import { logout } from '@/api/login' // 引入退出登录方法
// 初始化
const instance = axios.create({
  baseURL: process.env.VUE_APP_API_BASE_URL,
  timeout: 120 * 1000,
  withCredentials: true
})

// 请求错误
const err = (error: {
  message: string | string[]
  response: { data: any; status: number }
}) => {
  if (error.message.includes('timeout')) {
    notification.error({
      message: '系统提示',
      description: '请求超时',
      duration: 4
    })
  }
  if (error.response) {
    const data = error.response.data
    const token = localCache.getCache('token')
    if (error.response.status == 403) {
      notification.error({
        message: '系统提示',
        description: '请求资源失败',
        duration: 4
      })
    }
    if (
      error.response.status === 401 &&
      !(data.result && data.result.isLogin)
    ) {
      notification.error({
        message: '系统提示',
        description: '没有访问权限',
        duration: 4
      })
      // token 存在但是没有访问权限,退出登录
      if (token) {
        logout()
      }
    }
  }
  return Promise.reject(error)
}

// 请求
instance.interceptors.request.use((config: AxiosRequestConfig) => {
  // 获取系统token
  const token: string = store.state.token
  if (token) {
    config.headers['X-Access-Token'] = token // 让每个请求携带自定义 token 请根据实际情况自行修改
  }
  // 配置 get 接口默认参数携带时间戳请求
  if (config.method == 'get') {
    config.params = {
      _t: new Date().getTime(),
      ...config.params
    }
  }
  return config
}, err)

// 拦截成功请求
instance.interceptors.response.use((response: AxiosResponse) => {
  const config: AxiosRequestConfig = response.config || ''
  const code = Number(response.data.code)
  // code 状态根据前后端协定接口成功状态修改
  if (code == 200 || code == 0) {
    if (config) {
      console.log('请求成功')
    }
    return response.data
  } else {
    const errorCode = [402, 403, 500]
    if (errorCode.includes(response.data.code)) {
      notification.error({
        message: '系统提示',
        description: '没有权限',
        duration: 4
      })
      setTimeout(() => {
        window.location.reload()
      }, 500)
    }
  }
}, err)

export default instance

说明:初始化里面的baseURL的值直接读取 process.env.VUE_APP_API_BASE_URL,值的配置项来源于.env环境变量。其中.env所有环境都会被载入,.env.test测试环境被载入,.env.development开发环境被载入,.env.production生产环境被载入。文件的创建在项目的根目录和vue.config.js同级。具体配置项可参考Vue CLI 模式和环境变量open in new window

封装

在项目src文件夹下创建文件夹 api文件夹 ,并创建 manage.ts 文件,文件内容如下:

import axios from '@/utils/request'

/**
 * @desc post请求
 * @param url 请求路径
 * @param parameter 请求参数
 *  */
export function postAction(url: string, parameter: any) {
  return axios({
    url: url,
    method: 'post',
    data: parameter
  })
}

/**
 * @desc http请求
 * @param url 请求路径
 * @param parameter 请求参数
 * @param method= {post | put}
 *  */
export function httpAction(url: string, parameter: any, method: any) {
  return axios({
    url: url,
    method: method,
    data: parameter
  })
}

/**
 * @desc put请求
 * @param url 请求路径
 * @param parameter 请求参数
 *  */
export function putAction(url: string, parameter: any) {
  return axios({
    url: url,
    method: 'put',
    data: parameter
  })
}

/**
 * @desc get请求
 * @param url 请求路径
 * @param parameter 请求参数
 *  */
export function getAction(url: string, parameter: any) {
  return axios({
    url: url,
    method: 'get',
    params: parameter
  })
}

/**
 * @desc delete请求
 * @param url 请求路径
 * @param parameter 请求参数
 *  */
export function deleteAction(url: string, parameter: any) {
  return axios({
    url: url,
    method: 'delete',
    params: parameter
  })
}

vue.config.js 配置代理

  1. 在项目根目录创建vue.config.js 配置服务器请求代理
module.exports = {
  devServer: {
    port: 3082,
    proxy: {
      '/pr-api': {
        target: 'http://localhost:3085',
        ws: false,
        changeOrigin: true
      }
    }
  },

  lintOnSave: undefined
}

使用封装请求

import { postAction } from '@/api/manage'

postAction('/sys/tese', { id: '' }).then((res: any) => {
  if (res.success) {
  }
})