Axios
Axios 是一个基于 promise 的 HTTP 库,简单的讲就是可以发送 get、post 等请求。
为什么使用 Axios?为了方便使用网络请求。
为什么不使用 jQquery 的 Ajax?Vue 开发中不需要使用 jQuery,不必为了一个小小的网络请求而增加 jQuery。
Axios 特性
- 可以在浏览器中发送 XMLHttpRequests
- 可以在 node.js 发送 http 请求
- 支持 Promise API
- 拦截请求和响应
- 转换请求数据和响应数据
- 能够取消请求
- 自动转换 JSON 数据
- 客户端支持保护安全免受 XSRF 攻击
使用场景
在特性里面已经有提到,浏览器发送请求,或者 Node.js 发送请求都可以用到 Axios。像 Vue、React、Node 等项目就可以使用 Axios,如果你的项目里面用了 jQuery,此时就不需要多此一举了,jQuery 里面本身就可以发送请求。
安装
引入 CDN
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
引入完成后,会自动在页面注册一个全局 axios 变量。
npm 安装
npm install axios --save
使用
如果没有后台代码,那么我们可以使用 httpbin.org 这个网站进行测试。
GET 请求
axios.get(url).then(function(response){}, function(err){})
then
方法的第一个参数是在请求成功之后触发的函数,第二是在请求失败之后触发的函数;这两个函数都会有一个参数。如果在请求的 url 中传入参数,则应该按照以下的形式:axios.get(xxx?key1=value1&key2=value2)
POST 请求
和 GET 请求语法类似,但是 url 传参时应该传递一个对象,如下:
axios.post(xxx, {key1:value1,key2:value2})
示例
<form action=""> <input type="button" value="get请求" class="get"> <input type="button" value="post请求" class="post"> </form> <!-- 引入axios --> <!-- 导入之后,会在页面注册一个全局的 axios 变量 --> <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
// 以下参考 https://www.jianshu.com/p/9bcf0002ffa3 document.querySelector('.get').onclick = function() { // 生成三条笑话 axios.get("https://autumnfish.cn/api/joke/list?num=3") .then(function(response) { console.log(response) console.log(response.data.jokes) },function(error) { console.log(error) }) } // -----用户注册----- // 请求地址:https://autumnfish.cn/api/user/reg // 请求方法:post // 请求参数:username(用户名,字符串) // 响应内容:注册成功或失败 document.querySelector('.post').onclick = function() { axios.post("https://autumnfish.cn/api/user/reg", { username: "daijunfeng" }) .then(function(response) { console.log(response) }, function(error) { console.log(error) }) }
axios()
该方法其实是其它方法的一个基本使用,可支持任意方式的请求。该方法默认是 GET 请求。
// 导入 axios import axios from 'axios' /* --------------------- GET 请求 --------------------- */ // 无参 axios({ url: 'http://123.207.32.32:8000/home/multidata', method: 'get' }).then(data => { console.log(data) }) // 携带请求参数(也可直接拼接在 url 后面) axios({ url: 'http://123.207.32.32:8000/home/multidata', method: 'get', // 只针对 get 请求时,传递参数 params: { id: 1 } }).then(data => { console.log(data) }) /* --------------------- POST 请求 --------------------- */ // 无参 axios({ url: 'http://123.207.32.32:8000/home/multidata', method: 'post' }).then(data => { console.log(data) }) // 携带请求参数 axios({ url: 'http://123.207.32.32:8000/home/multidata', method: 'post', // post请求时,传递参数 data: { id: 1 } }).then(data => { console.log(data) }) /* --------------------- 并发请求 --------------------- */ axios.all([ axios({ url: 'http://123.207.32.32:8000/home/multidata' }), axios({ url: 'http://123.207.32.32:8000/home/multidata' }) ]).then(results => { console.log(results) }) // 将多个请求的结果分开 axios.spread axios.all([ axios({ url: 'http://123.207.32.32:8000/home/multidata' }), axios({ url: 'http://123.207.32.32:8000/home/multidata' }) ]).then(axios.spread((r1, r2) => { console.log(r1, r2) }))
眼熟的方法
then()
。在 Promise 中,我们提到过,异步请求的回调结果会在这个方法中执行。其实 Axios 请求之后就是返回的一个 Promise 对象,所以,我们可以在 axios 中使用 Promise API。
在某些情况下,我们的 URL 中可能存在重复的部分,我们可以使用 baseURL 将这些重复的部分提取出来:
axios.all([
axios({
baseURL: 'http://123.207.32.32:8000',
url: '/home/multidata'
}),
axios({
baseURL: 'http://123.207.32.32:8000',
// 超时时间为 5s
timeout: 5000,
url: '/home/multidata'
})
]).then(axios.spread((r1, r2) => {
console.log(r1, r2)
}))
但是,上面的示例并没有太大的用处,所以我们需要进一步配置。
axios 全局配置
全局配置主要用来配置所有请求的公共部分,如 baseURL、timeout 等。
// 全局配置
axios.defaults.baseURL = 'http://123.207.32.32:8000'
axios.defaults.timeout = 5000
axios.all([
axios({
url: '/home/multidata'
}),
axios({
url: '/home/multidata'
})
]).then(axios.spread((r1, r2) => {
console.log(r1, r2)
}))
axios 实例
在上面的代码中,我们是直接使用的是全局的 Axios,并没有创建它的实例。如果我们想要在请求中进行不同配置,那么,我们可以创建它的实例。
// 进行公共配置
const instance = axios.create({
baseURL: 'http://123.207.32.32:8000',
timeout: 5000
})
instance({
url: '/home/multidata',
headers: {
}
}).then(val => {
console.log(val)
})
好了,在经过上面的学习,我们已经知道了如何发送网络请求。现在,我们需要实现一个功能:当页面加载完成后渲染数据库里面的 数据。我们的思路可能是:在组件的 created()
函数中发送网络请求即可,如下:
<template>
<div id="app">
<div>{{ data }}</div>
</div>
</template>
<script>
import axios from 'axios'
export default {
name: 'App',
components: {
},
data() {
return {
data: null
}
},
created() {
axios({
url: 'http://123.207.32.32:8000/home/multidata'
}).then(val => {
this.data = val
})
}
}
</script>
Axios 封装
上面的代码虽然可以实现功能,但是,我们却不推荐这样使用,因为组件对框架的依赖性太强了,而且如果所有组件都这样使用的话,代码维护起来会很麻烦,所以,我们就可以对网络请求进行封装。
src/network/request.js
import Axios from 'axios' export function request(config) { const axios = Axios.create({ baseURL: 'http://123.207.32.32:8000', timeout: 5000 }) // axios 返回的就是 promise return axios(config) } /*----------------------自己封装 Promise ----------------------*/ // export function request(config) { // return new Promise((resolve, reject) => { // const axios = Axios.create({ // baseURL: 'http://123.207.32.32:8000', // timeout: 5000 // }) // axios(config) // .then(data => { // resolve(data) // }).catch(err => { // reject(err) // }) // }) // } /*----------------------封装方式三 ----------------------*/ // export function request(config, success, error) { // const axios = Axios.create({ // baseURL: 'http://123.207.32.32:8000', // timeout: 5000 // }) // axios(config).then(data => { // success(data) // }).catch(err => { // error(err) // }) // } // export function request(config) { // const axios = Axios.create({ // baseURL: 'http://123.207.32.32:8000', // timeout: 5000 // }) /*----------------------封装方式四 ----------------------*/ // axios(config.baseConfig).then(data => { // config.success(data) // }).catch(err => { // config.error(err) // }) // }
使用封装后的函数:
import {request} from './network/request'
/* ------------- 方式一、二 ---------- */
request({
url: '/home/multidata'
}).then(data => {
console.log(data)
}).catch(err => {
console.log(err)
})
/* ------------- 方式三 ---------- */
// request(
// {
// url: '/home/multidata',
// },
// data => {
// console.log(data)
// },
// err => {
// console.log(err)
// }
// )
/* ------------- 方式四 ---------- */
// request({
// baseConfig: {
// url: '/home/multidata'
// },
// success: data => {
// console.log(data)
// },
// error: err => {
// console.log(err)
// }
// })
拦截器
Axios 提供了拦截器,用于我们在发送请求前或得到结果后,进行相应的处理。
Axios 提供了四种拦截:
- 请求成功
- 请求失败
- 响应成功
- 响应失败
export function request(config) {
const axios = Axios.create({
baseURL: 'http://123.207.32.32:8000',
timeout: 5000
})
// 拦截请求
axios.interceptors.request.use(success => {
// 其实该参数就是我们传递的 config
// console.log(success)
// 可以在这里修改我们之前传入的信息
// 也可以在发送请求时添加动画
// 验证用户的 token,是否已登录
// 放行
return success
}, err => {
console.log(err)
})
// 拦截响应
axios.interceptors.response.use(result => {
// console.log(result)
// 返回结果,只返回我们需要的数据
return result.data
}, error => {
console.log(error)
})
// axios 返回的就是 promise
return axios(config)
}
示例
axios 和 Vue
<div id="app"> <button id="btn" @click="myClick">获取笑话</button> <button id="btn" @click="myRegister">注册</button><br><br> <div v-html="message">123</div> </div> <!-- 引入 axios --> <script src="https://unpkg.com/axios/dist/axios.min.js"></script> <!-- 引入 Vue --> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vuejs"></script>
var app = new Vue({ el: '#app', data: { message: '' }, methods: { myClick: function() { // 注意 axios 里面的回调函数中的 this 已经不再是 Vue var that = this axios.get("https://autumnfish.cn/api/joke/list?num=3") .then(function(response) { var jokes = response.data.jokes for (var i = 0; i < jokes.length; i++) { that.message += jokes[i] + "<br>" console.log(that.message) } }, function(error) { this.message = '请求出错' }) }, myRegister: function() { var that = this axios.post("https://autumnfish.cn/api/user/reg", { username: "daijunfeng" }).then(function(response) { // console.log(response) alert(response.data) }, function(error) { alert("注册出错") }) } } })
提示
在 axios 回调函数中的 this
指向已经发生改变,所以要把外部的 this
保存起来再使用。
天气查询
<div id="app"> <!-- 使用 v-model 双向绑定数据 --> <input type="text" v-model="city" @keyup.enter="myClick"> <button @click="myClick">查询天气</button><br> 热门城市: <a href="javascript:;" @click="changeCity('北京')">北京</a> | <a href="javascript:;" @click="changeCity('上海')">上海</a> | <a href="javascript:;" @click="changeCity('深圳')">深圳</a><br> {{ message?'当前温度: '+message:''}} <ul> <li v-for="(ele,i) in arr"> {{ ele.date }} -> {{ ele.fengxiang }} -> {{ ele.high }} -> {{ ele.low }} -> {{ ele.type }} </li> </ul> </div> <!-- 引入 axios --> <script src="https://unpkg.com/axios/dist/axios.min.js"></script> <!-- 引入 Vue --> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vuejs"></script>
var app = new Vue({ el: '#app', data: { message: '', city: '', arr: [] }, methods: { myClick: function() { var that = this // 此处使用 http,使用 https 时会出现跨域 // 注意,在 get 方法里面还是能使用 this axios.get('http://wthrcdn.etouch.cn/weather_mini?city=' + this.city) .then(function(response) { console.log(response) that.arr = response.data.data.forecast that.message = response.data.data.wendu }, function(error) { console.log('请求错误') console.log(error) }) }, // 点击查询 changeCity: function(city) { this.city = city this.myClick() } } })
音乐播放器
<!DOCTYPE html> <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>悦听player</title> <!-- 样式 --> <link rel="stylesheet" href="./css/index.css"> </head> <body> <div class="wrap"> <!-- 播放器主体区域 --> <div class="play_wrap" id="player"> <div class="search_bar"> <img src="images/player_title.png" alt="" /> <!-- 搜索歌曲 --> <input type="text" autocomplete="off" v-model="music" @keyup.enter="searchMusic" /> </div> <div class="center_con"> <!-- 搜索歌曲列表 --> <div class='song_wrapper'> <ul class="song_list"> <li v-for="(ele,i) in musicArr" :key="i"> <!-- 播放按钮 --> <a href="javascript:;" @click="playMusic(ele.id)"></a> <!-- 歌名 --> <b>{{ ele.name }}</b> <!-- 是否有 MV --> <span v-if="ele.mvid!=0" @click="getMV(ele.mvid)"><i></i></span> </li> </ul> <img src="images/line.png" class="switch_btn" alt=""> </div> <!-- 歌曲信息容器 --> <!-- :class="{playing:isPlay}" 等价于 :class="isPlay?:'playing':''" --> <!-- 类名 playing 增加封面旋转效果 --> <div class="player_con" :class="{playing:isPlay}"> <img src="images/player_bar.png" class="play_bar" /> <!-- 黑胶碟片 --> <img src="images/disc.png" class="disc autoRotate" /> <!-- 歌曲封面 --> <img :src="picUrl==''?'images/wyyyy.png':picUrl" class="cover autoRotate" /> </div> <!-- 评论容器 --> <div class="comment_wrapper"> <h5 class='title'>热门留言</h5> <div class='comment_list'> <dl v-for="(ele,i) in hotComments" :key="i"> <!-- :src 为评论用户的头像 --> <dt><img :src="ele.user.avatarUrl" alt=""></dt> <dd class="name">{{ ele.user.nickName }}</dd> <dd class="detail"> {{ ele.content }} </dd> </dl> </div> <img src="images/line.png" class="right_line"> </div> </div> <!-- 底部播放音频按钮 --> <div class="audio_con"> <audio ref='audio' :src="musicUrl" controls autoplay loop class="myaudio" @play="play" @pause="pause"></audio> </div> <!-- 播放视频按钮 --> <div class="video_con" v-show="isShowMv"> <video controls="controls" :src="mvUrl"></video> <div class="mask" @click="closeMv"></div> </div> </div> </div> <!-- 开发环境版本,包含了有帮助的命令行警告 --> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <!-- 官网提供的 axios 在线地址 --> <script src="https://unpkg.com/axios/dist/axios.min.js"></script> <script src="./js/music.js"></script> </body> </html>
/* 1:歌曲搜索接口 请求地址:https://autumnfish.cn/search 请求方法:get 请求参数:keywords(查询关键字) 响应内容:歌曲搜索结果 2:歌曲url获取接口 请求地址:https://autumnfish.cn/song/url 请求方法:get 请求参数:id(歌曲id) 响应内容:歌曲url地址 3.歌曲详情获取 请求地址:https://autumnfish.cn/song/detail 请求方法:get 请求参数:ids(歌曲id) 响应内容:歌曲详情(包括封面信息) 4.热门评论获取 请求地址:https://autumnfish.cn/comment/hot?type=0 请求方法:get 请求参数:id(歌曲id,地址中的type固定为0) 响应内容:歌曲的热门评论 5.mv地址获取 请求地址:https://autumnfish.cn/mv/url 请求方法:get 请求参数:id(mvid,为0表示没有mv) 响应内容:mv的地址 */ var app = new Vue({ el: '#player', data: { music: '', musicArr: '', musicUrl: '', picUrl: '', hotComments: [], isPlay: false, isShowMv: false, mvUrl: '' }, methods: { // 搜索歌曲 searchMusic: function() { var that = this axios.get('https://autumnfish.cn/search?keywords=' + this.music) .then(function(res) { console.log(res) that.musicArr = res.data.result.songs }, function(err) { alert('访问出错') }) }, // 播放歌曲 playMusic: function(musicId) { var that = this // 获取音乐 axios.get('https://autumnfish.cn/song/url?id=' + musicId) .then(function(res) { // console.log(res) that.musicUrl = res.data.data[0].url }, function(err) { alert("获取歌曲信息失败") }) // 获取封面 axios.get('https://autumnfish.cn/song/detail?ids=' + musicId) .then(function(res) { // console.log(res) that.picUrl = res.data.songs[0].al.picUrl }, function(err) { alert("封面获取失败") }) // 获取热门评论 axios.get('https://autumnfish.cn/comment/hot?type=0&id=' + musicId) .then(function(res) { // console.log(res) that.hotComments = res.data.hotComments console.log(that.hotComments.length) }, function(err) { alert('获取评论失败') }) }, // 音乐播放 play: function() { this.isPlay = true }, // 音乐暂停 pause: function() { this,this.isPlay = false }, // 获取 MV getMV: function(mvId) { var that = this // 此处不判断 mvId 是否为 0,直接在前台判断来显示或隐藏 mv 的图标 axios.get('https://autumnfish.cn/mv/url?id=' + mvId) .then(function(res) { // console.log(res) that.mvUrl = res.data.data.url that.isShowMv = true }, function(err) { alert('MV 获取失败') }) }, // 点击遮罩层,mv关闭 closeMv: function() { this.isShowMv = false this.mvUrl = '' } } })
强调
只要在一个地方修改了某个值,如果其它地方也使用了该值,则该值会跟着改变,这就是 Vue 的响应式(Reactive)。
提示
使用任何的 Vue 操作(指令)时,该元素必须是在 Vue 的一个实例中。