目录
一、初识 axios
1.1 什么是 axios
一个专门用于发送ajax请求的库
通过 npm install axios 安装
ajax原理?
浏览器window接口的XMLHttpRequest
特点 :
- 支持客户端发送Ajax请求
- 支持服务端Node.js发送请求
- 支持Promise相关用法
- 支持请求和响应的拦截器功能
- 自动转换JSON数据
- axios 底层还是原生js实现, 内部通过Promise封装的
语法:
axios({
method: '请求方式', // get/post
url: '请求地址',
data: { // 拼接到请求体的参数,post请求的参数
xxx: yyy
}, // 参数名和值会被axios拼接到请求体里
params: { // 拼接到请求体的参数,get请求的参数
xxx: yyy
} // 参数名和值会被axios拼接到url?后面--查询字符串
}).then(res => {
console.log(res.data);// 后台返回去的结果
}).catch(err => {
console.log(err); // 后台报错返回
})
1.2 使用 axios 发送ajax 请求
About.vue
<template>
<div class="about">
<h1 @click="handleClick">This is an about page</h1>
<h1>{{name}}</h1>
</div>
</template>
<script>
import {toRefs} from 'vue';
import {useStore} from 'vuex';
export default {
name: 'About',
setup(){
const store = useStore();
const {name}=toRefs(store.state);
const handleClick=()=>{
store.dispatch('getData');
}
return{
name,
handleClick
}
}
}
</script>
Home.vue
<template>
<div class="home">
<img alt="Vue logo" src="../assets/logo.png">
<h1>{{name}}</h1>
</div>
</template>
<script>
import {toRefs} from 'vue';
import {useStore} from 'vuex';
export default {
name: 'Home',
setup(){
const store = useStore();
const {name}=toRefs(store.state);
return{
name
}
}
}
</script>
store/index.js
import { createStore } from 'vuex';
import axios from 'axios';
//VueX 数据管理框架
//VueX 创建了一个全局唯一的仓库,用来存放全局的数据
export default createStore({
// 存放全局的数据
state: {
name: 'dell'
},
//mutation 里面只允许写同步代码,不允许写异步代码
//commit和mutation作关联
mutations: {
//第四步,对应的 mutation 被执行
changeName(state, str) {
//第五步 在 mutation 里修改数据
// this.state.name = 'lee';
state.name = str;
}
},
// dispatch 和 actions 作关联
actions: {
//第二步,store 感知到了你触发了一个叫做 change 的 action
//执行 change()方法
getData(store) {
axios.get('https://www.fastmock.site/mock/ae8e9031947a302fed5f92425995aa19/jd/api/user/register')
.then((res) => {
const msg = res.data.meaasge;
// console.log(msg);
//第三步,提交一个 commit,触发一个 mutation
store.commit('changeName', msg);
})
}
},
modules: {}
})
二、axios方式GET/POST请求
axios参考文档 :使用说明 · Axios 中文说明 · 看云
公共部分:
App.vue
<template>
<div id="app">
<HelloWorld />
</div>
</template>
<script>
import HelloWorld from './components/HelloWorld.vue'
export default {
name: 'App',
components: {
HelloWorld
}
}
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
2.1 发送GET请求
<template>
<div>
<h3>axios</h3>
<p>{{info.title}}</p>
<p>{{info.content}}</p>
</div>
</template>
<script>
import axios from "axios"
export default {
name: 'HelloWorld',
data () {
return {
info:{
title:"",
content:""
}
}
},
mounted () {
//方式1
// 为给定 ID 的 user 创建请求
// axios.get('http://iwenwiki.com/api/blueberrypai/getIndexChating.php')
// .then(res=> {
// // console.log(res.data);
// // console.log(res.data.chating);
// // console.log(res.data.chating[1]);
// if(res.status === 200){
// this.info.content=res.data.chating[1].content;
// this.info.title=res.data.chating[1].title;
// }
// })
// .catch(error=> {
// console.log(error);
// });
//方式2
axios.get('http://iwenwiki.com:3000/search',{
params:{
keywords:"海阔天空"
}
})
.then(res=> {
console.log(res.data.result.songs);
})
.catch(error=> {
console.log(error);
});
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h3 {
margin: 40px 0 0;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
a {
color: #42b983;
}
</style>
方式1,
方式2,
2.2 发送POST
注意:
post接收参数的类型为:user_id=123&password=a45789
因此需要用到 querystring 来做类型转换
<template>
<div>
<h3>axios</h3>
</div>
</template>
<script>
import axios from "axios"
import qs from "querystring"
export default {
name: 'HelloWorld',
mounted () {
axios.post('http://iwenwiki.com/api/blueberrypai/login.php', qs.stringify({
user_id: 'iwen@qq.com',
password: 'iwen123',
verification:'crfvw'
}))
.then(res=> {
console.log(res.data);
})
.catch(error=> {
console.log(error);
});
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h3 {
margin: 40px 0 0;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
a {
color: #42b983;
}
</style>
三、全局配置及请求响应拦截器
公共部分:
App.vue
<template>
<div id="app">
<HelloWorld />
</div>
</template>
<script>
import HelloWorld from './components/HelloWorld.vue'
export default {
name: 'App',
components: {
HelloWorld
}
}
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
3.1 全局配置
<template>
<div>
<h3>axios</h3>
<p>{{info.title}}</p>
<p>{{info.content}}</p>
</div>
</template>
<script>
import qs from "querystring"
export default {
name: 'HelloWorld',
data () {
return {
info:{
title:"",
content:""
}
}
},
mounted () {
// GET请求方式一
this.$axios.get("http://iwenwiki.com:3000/search?keywords=海阔天空")
.then(res =>{
console.log(res.data);
})
.catch(error =>{
console.log(error);
})
// GET请求方式二
this.$axios.get("http://iwenwiki.com:3000/search",{
params:{
keywords:"泸沽湖"
}
}).then(res =>{
console.log(res.data);
}).catch(error =>{
console.log(error);
})
//post请求
this.$axios.post('/api/blueberrypai/login.php', qs.stringify({
user_id:"iwen@qq.com",
password:"iwen123",
verification_code:"crfvw"
}))
.then(res=> {
console.log(res.data);
})
.catch(error=> {
console.log(error);
});
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h3 {
margin: 40px 0 0;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
a {
color: #42b983;
}
</style>
main.js
import Vue from 'vue'
import App from './App.vue'
import './registerServiceWorker'
import axios from "axios"
//配置公共地址
axios.defaults.baseURL = 'http://iwenwiki.com';
// axios.defaults.headers.common['Authorization'] = AUTH_TOKEN;
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
//将其挂载到原型上,以便于引用
Vue.prototype.$axios = axios
Vue.config.productionTip = false
new Vue({
render: h => h(App),
}).$mount('#app')
3.2 拦截器
<template>
<div>
<h3>axios</h3>
<p>{{info.title}}</p>
<p>{{info.content}}</p>
</div>
</template>
<script>
import qs from "querystring"
export default {
name: 'HelloWorld',
data () {
return {
info:{
title:"",
content:""
}
}
},
mounted () {
// GET请求方式一
this.$axios.get("http://iwenwiki.com:3000/search?keywords=海阔天空")
.then(res =>{
console.log(res.data);
})
.catch(error =>{
console.log(error);
})
// GET请求方式二
this.$axios.get("http://iwenwiki.com:3000/search",{
params:{
keywords:"泸沽湖"
}
}).then(res =>{
console.log(res.data);
}).catch(error =>{
console.log(error);
})
//post请求
this.$axios.post('/api/blueberrypai/login.php', {
user_id:"iwen@qq.com",
password:"iwen123",
verification_code:"crfvw"
})
.then(res=> {
console.log(res.data);
})
.catch(error=> {
console.log(error);
});
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h3 {
margin: 40px 0 0;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
a {
color: #42b983;
}
</style>
main.js
import Vue from 'vue'
import App from './App.vue'
import './registerServiceWorker'
import axios from "axios"
import qs from 'querystring'
//配置公共地址
axios.defaults.baseURL = 'http://iwenwiki.com';
// axios.defaults.headers.common['Authorization'] = AUTH_TOKEN;
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
//拦截器
//请求拦截
axios.interceptors.request.use(
config => {
if (config.method === 'post') {
//转换
config.data = qs.stringify(config.data)
}
// console.log(config);
return config
},
error => Promise.reject(error)
)
//响应拦截
axios.interceptors.response.use(
response => {
return response
},
error => Promise.reject(error)
)
//将其挂载到原型上,以便于引用
Vue.prototype.$axios = axios
Vue.config.productionTip = false
new Vue({
render: h => h(App),
}).$mount('#app')
四、封装及跨域配置
项目大致结构:
src里:
跨域产生的原因:
域名、端口、二级域名等不同会产生跨域
4.1 跨域解决方案
1. 前端
1. 生产环境
jsonp
2. 开发环境
proxy代理方式
2. 后端
cors方式
4.2 示例
App.vue
<template>
<div id="app">
<HelloWorld msg="Welcome to Your Vue.js App"/>
</div>
</template>
<script>
import HelloWorld from './components/HelloWorld.vue'
export default {
name: 'App',
components: {
HelloWorld
}
}
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
main.js
import Vue from 'vue'
import App from './App.vue'
import './registerServiceWorker'
Vue.config.productionTip = false
new Vue({
render: h => h(App),
}).$mount('#app')
vue.config.js
module.exports = {
devServer: {
proxy: {
'/api': {
target: 'http://iwenwiki.com/',
changeOrigin: true,
pathRewrite: { // 路径重写
"^/api": ""
}
}
}
}
}
src/utils/request.js
import axios from "axios"
import qs from "querystring"
/**
* 3.处理错误信息
* status:状态码
* info:具体信息
*/
const errorHandle = (status, info) => {
switch (status) {
case 400:
console.log("语义错误");
break;
case 401:
console.log("服务器认证失败");
break;
case 403:
console.log("服务器请求拒绝执行");
break;
case 404:
console.log("请检查网路请求地址");
break;
case 500:
console.log("服务器发生意外");
break;
case 502:
console.log("服务器无响应");
break;
default:
console.log(info);
break;
}
}
/**
* 1.创建Axios对象
*/
const instance = axios.create({
// 公共配置
// baseURL: "http://iwenwiki.com",//处理跨域时需要将其注释掉
timeout: 5000,
//跨域请求时,是否需要凭证
// withCredentials: true
})
/**
* 2.拦截器
*/
//请求拦截
instance.interceptors.request.use(
config => {
if (config.method === 'post') {
// token:登陆信息凭证
config.data = qs.stringify(config.data)
}
return config
},
error => Promise.reject(error)
)
// 响应拦截
instance.interceptors.response.use(
// 完成了
response => response.status === 200 ? Promise.resolve(response) : Promise.reject(response),
error => {
// 错误信息的处理
const { response } = error;
if (response) {
errorHandle(response.status, response.info)
} else {
console.log("网络请求被中断了");
}
}
)
// get和post等请求方案
export default instance
src/api/index.js
import axios from "../utils/request"
/**
* 所有的网络请都写在这里
*/
const base = {
// baseUrl: "/",//非跨域
baseUrl: "/api", //解决跨域
banner: "/api/FingerUnion/list.php" // 首页banner路径
}
const api = {
/**
* 首页 banner位数据获取
*/
getBanner() {
return axios.get(base.baseUrl + base.banner)
}
}
export default api
Helloword.vue
<template>
<div class="hello">
<h1>{{ msg }}</h1>
</div>
</template>
<script>
import api from "../api"
export default {
name: 'HelloWorld',
props: {
msg: String
},
mounted(){
api.getBanner().then(res =>{
console.log(res.data);
}).catch(error =>{
console.log(error);
})
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h3 {
margin: 40px 0 0;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
a {
color: #42b983;
}
</style>
非跨域,
跨域,
五、创建服务器提供数据实践
5.1 前期准备
npm install --save axios
npm install --save express
项目结构:
App.vue
<template>
<div>
<ServeDemo />
</div>
</template>
<script>
import ServeDemo from "./components/ServeDemo.vue"
export default {
name: 'App',
components: {
ServeDemo
}
}
</script>
<style>
</style>
ServeDemo.vue
<template>
<div>
hi
</div>
</template>
<script>
import api from "../api"
export default {
name:"ServeDemo",
mounted () {
api.getList({
page:2
}).then(res=>{
console.log(res.data);
}).catch(error=>{
console.log(error);
})
}
}
</script>
<style>
</style>
vue.config.js
module.exports = {
devServer: {
proxy: {
'/api': {
target: 'http://localhost:3000/',
changeOrigin: true,
pathRewrite: { // 路径重写
"^/api": ""
}
}
}
}
}
serve/index.js
//引入express并创建express对象
const express = require("express");
const app = express();
// 引入
const router = require("./router");
//处理post请求
const bodyParser = require("body-parser");
//post
app.use(bodyParser.urlencoded({
extended: true
}))
app.use("/", router);
//设置监听端口
app.listen(3000, () => {
console.log("server running at port 3000");
})
serve/router.js
//引入express
const express = require("express");
//创建路由对象
const router = express.Router();
//get接收参数--引入url
const url = require("url");
//
const list = require("./data/list")
// get请求
router.get("/list", (req, res) => {
const page = url.parse(req.url, true).query.page;
// 发送数据
res.send({
status: 200,
result: list,
page
})
})
// post请求
router.post("/login", (req, res) => {
const username = req.body.username;
const password = req.body.password;
res.send({
status: 200,
username,
password
})
})
//导出 router
module.exports = router;
serve/data/list.js
module.exports = [
{
id:1001,
name:"衣服"
},
{
id:1002,
name:"鞋子"
},
{
id:1003,
name:"电脑"
}
]
src/api/index.js
import axios from "../utils/request"
const base = {
// baseUrl: "http://localhost:3000",
baseUrl: "/api",
list: "/list"
}
const api = {
getList(params) {
return axios.get(base.baseUrl + base.list, {
params
})
}
}
export default api;
src/utils/request.js
import axios from "axios"
import qs from "querystring"
/**
* 处理错误信息
* status:状态吗
* info:具体信息
*/
const errorHandle = (status,info) =>{
switch(status){
case 400:
console.log("语义错误");
break;
case 401:
console.log("服务器认证失败");
break;
case 403:
console.log("服务器请求拒绝执行");
break;
case 404:
console.log("请检查网路请求地址");
break;
case 500:
console.log("服务器发生意外");
break;
case 502:
console.log("服务器无响应");
break;
default:
console.log(info);
break;
}
}
/**
* 创建Axios对象
*/
const instance = axios.create({
// 公共配置
// baseURL:"http://iwenwiki.com",
timeout:5000,
// withCredentials: true
})
/**
* 拦截器
*/
instance.interceptors.request.use(
config =>{
if(config.method === 'post'){
// token:登陆信息凭证
config.data = qs.stringify(config.data)
}
return config
},
error => Promise.reject(error)
)
instance.interceptors.response.use(
// 完成了
response => response.status === 200 ? Promise.resolve(response) : Promise.reject(response),
error =>{
// 错误信息的处理
const { response } = error;
if(response){
errorHandle(response.status,response.info)
}else{
console.log("网络请求被中断了");
}
}
)
// get和post等请求方案
export default instance
通过 node index.js 运行服务器
通过 npm run serve 运行前端
GET请求,
POST请求,通过 postman来进行