Vue实现前后端交互方式(Promise、fetch、axios、async/await)

1. 前后端交互模式

1.1 接口调用方式

  • 原生Ajax
  • 基于jQuery的ajax
  • fetch
  • axios
    在这里插入图片描述

1.2 URL地址格式

1. 传统形式的URL

  • 格式:schema://host:port/path?query#fragment
    ① schema:协议。例如http、https、ftp等
    ② host:域名或者IP地址
    ③ port:端口,http默认端口80,可以省路
    ④ path:路径,例如/abc/a/b/c
    ⑤ query:查询参数,例如 uname=lisi&age=12
    ⑥ fragment:锚点(哈希Hash),用于定位页面的某个位置
  • 符合规则的URL
    ① http://www.itcast.cn
    ② http://www.itcast.cn/java/web
    ③ http://www.itcast.cn/java/web?flag=1
    ④ http://www.itcast.cn/java/web?flag=1#function

2. Restful形式的URL

  • HTTP请求方式
    ① GET 查询
    ② POST 添加
    ③ PUT 修改
    ④ DELETE 删除
  • 符合规则的URL地址
    ① http://www.hello.com/books GET
    ② http://www.hello.com/books POST
    ③ http://www.hello.com/books/123 PUT
    ④ http://www.hello.com/books/123 DELETE

2. Promise用法

2.1 异步调用

  • 异步效果分析
    ① 定时任务
    ② Ajax
    ③ 事件函数
  • 多次异步调用的依赖分析
    ① 多次异步调用的结果顺序不确定
// 三者的顺序不确定
$.ajax({
    url:'http://localhost:3000/data',
    success:function(data){
        console.log(data)
    }
});
$.ajax({
    url:'http://localhost:3000/data1',
    success:function(data){
        console.log(data)
    }
});
$.ajax({
    url:'http://localhost:3000/data2',
    success:function(data){
        console.log(data)
    }
});

② 异步调用结果如果存在依赖需要嵌套(出现回调地狱)

$.ajax({
    url:'http://localhost:3000/data',
    success:function(data){
        console.log(data)
        $.ajax({
            url:'http://localhost:3000/data1',
            success:function(data){
                console.log(data)
                $.ajax({
                    url:'http://localhost:3000/data2',
                    success:function(data){
                        console.log(data)
                    }
                });
            }
        });
    }
});

2.2 Promise概述

Promise是异步编程的一种解决方案,从语法上讲, Promise是一个对象,从它可以获取异步操作的消息。

使用 Promise主要有以下好处:

  • 可以避免多层异步调用嵌套问题(回调地狱)
  • Promise对象提供了简洁的APl,使得控制导步操作更加容易

官方文档:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise

2.3 Promise基本用法

  • 实例化Promise对象,构造函数中传递函数,该函数中用于处理异步任务
  • resolvereject两个参数用于处理成功和失败两种情况,并通过p.then获取处理结果
var p = new Promise(function(resolve,reject){
    // 成功时调用 resolve()
    resolve(data)
    // 失败时调用 reject()
    reject(err)
});

p.then(function(data){
    // 从resolve得到正常结果,data为resolve中的参数
},function(err){
    // 从reject得到错误信息,err为reject中的参数
});

补充:Promise的链式调用

  1. 成功请求普通写法
new Promise((resolve,reject)=>{
    // 模拟网络请求
    setTimeout(()=>{
        resolve('aaa')
    },1000)
}).then(res=>{
    console.log(res); //aaa
    return new Promise(resolve=>{
        resolve('bbb')
    })
}).then(res=>{
    console.log(res); //bbb
    return new Promise(resolve=>{
        resolve('ccc')
    })
}).then(res=>{
    console.log(res) //ccc
})
  1. 成功请求简单写法(对上述过程化简)
new Promise((resolve,reject)=>{
    // 模拟网络请求
    setTimeout(()=>{
        resolve('aaa')
    },1000)
}).then(res=>{
    console.log(res); //aaa
    return Promise.resolve('bbb')
}).then(res=>{
    console.log(res); //bbb
    return Promise.resolve('ccc')
}).then(res=>{
    console.log(res) //ccc
})
  1. 失败请求简单写法
new Promise((resolve,reject)=>{
    // 模拟网络请求
    setTimeout(()=>{
       resolve('aaa')
    },1000)
}).then(res=>{
    console.log(res) // aaa
    return Promise.reject('error message')
    // 上面这句话也可以这样调用
    // throw 'error message'
}).then(res=>{
    console.log(res) // 这句话不执行
}).catch(err=>{
    console.log(err) // error message
})

2.4 基于Promise处理Ajax请求

1. 处理原生Ajax

function queryData(url){
    var p = new Promise(function(resolve,reject){
        var xhr = new XMLHttpRequest();
        xhr.onreadystatechange = function(){
            if(xhr.readyState != 4) return;
            if(xhr.readyState == 4 && xhr.status == 200){
                // 处理正常情况
                resolve(xhr.responseText)
            }else{
                // 处理异常情况
                reject('服务器错误')
            }
        };
        xhr.open('get',url)
        xhr.send(null)
    });
    return p
}

queryData('http://localhost:3000/data')
    .then(function(data){
        console.log(data)
    },function(info){
        console.log(info)
    });

2. 发送多次Ajax请求

queryData('http://localhost:3000/data')
    .then(function(data){
        console.log(data)
        return queryData('http://localhost:3000/data1')
    })
    .then(function(data){
        console.log(data)
        return queryData('http://localhost:3000/data2')
    })
    .then(function(data){
        console.log(data)
    });

2.5 then参数中的函数返回值

  1. 返回Promise实例对象
  • 返回该实例对象会调用下一个then
  1. 返回普通值
  • 返回的普通值会直接传递给下一个then,通过then参数中函数的参数接收该值
function queryData(url){
    return new Promise(function(resolve,reject){
        var xhr = new XMLHttpRequest();
        xhr.onreadystatechange = function(){
            if(xhr.readyState != 4) return;
            if(xhr.readyState == 4 && xhr.status == 200){
                // 处理正常情况
                resolve(xhr.responseText)
            }else{
                // 处理异常情况
                reject('服务器错误')
            }
        };
        xhr.open('get',url)
        xhr.send(null)
    });
}
queryData('http://localhost:3000/data')
    .then(function(data){
        return queryData('http://localhost:3000/data1')
    })
    .then(function(data){
        return new Promise(function(resolve,reject){
            setTimeout(function(){
                resolve(123)
            },1000)
        })
    })
    .then(function(data){
        // 1
        console.log(data) // 123
        // 2 产生一个默认的promise实例对象
        return 'hello'
    })
    .then(function(data){
        console.log(data) // hello
    });

2.6 Promise常用的API

1. 实例方法

  • p.then() 得到异步任务的正确结果
  • p.catch() 获取异常信息
  • p.finally() 成功与否都会执行(尚且不是正式标准)
function foo(){
    return new Promise(function(resolve,reject){
        setTimeout(function(){
            resolve(123)
            // reject('error')
        },100)
    })
}


foo()
.then(function(data){
    console.log(data) // 正常时执行 123
})
.catch(function(data){
    console.log(data) // 异常时执行 error
})
.finally(function(){
    console.log('finished') // 无论正常、异常都执行
})
  1. 对象方法
  • Promise.all() 并发处理多个异步任务,所有任务都执行完成才能得到结果
  • Promise.race() 并发处理多个异步任务,只要有一个任务完成就能得到结果
function queryData(url){
    return new Promise(function(resolve,reject){
        var xhr = new XMLHttpRequest();
        xhr.onreadystatechange = function(){
            if(xhr.readyState != 4) return;
            if(xhr.readyState == 4 && xhr.status == 200){
                // 处理正常情况
                resolve(xhr.responseText)
            }else{
                // 处理异常情况
                reject('服务器错误')
            }
        };
        xhr.open('get',url)
        xhr.send(null)
    });
}
var p1 = queryData('http://localhost:3000/a1')
var p2 = queryData('http://localhost:3000/a2')
var p3 = queryData('http://localhost:3000/a3')

Promise.all([p1,p2,p3]).then(function(result){
	console.log(result)
}) // 返回后台全部结果
Promise.race([p1,p2,p3]).then(function(result){
	console.log(result)
}) // 返回第一个返回的结果

3. 接口调用-fetch用法

3.1 fetch概述

1. 基本特征

  • 更加简单的数据获取方式,功能更强大、更灵活,可以看做是xhr的升级版
  • 基于Promise实现

2. 语法结构

fetch(url)
	.then(fn2)
	.then(fn3)
	...
	.catch(fn)

官方文档:https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API

3.2 fetch的基本用法

fetch('/abc').then(data => {
	return data.text() // 返回一个Promise实例对象
}).then(ret=>{
	// 注意这里得到的才是最终的数据
	console.log(ret)
})

text()方法属于fetchAPI的一部分,它返回一个Promise实例对象,用于获取后台返回的数据

3.3 fetch请求参数

1. 常用配置选项

  • method(String):HTTP请求方法,默认为GET(GET、POST、PUT、DELETE)
  • body(String):HTTP的请求参数
  • headers(Object):HTTP的请求头,默认为{}
fetch('/abc',{
	method:'GET'
}).then(data => {
	return data.text() // 返回一个Promise实例对象
}).then(ret=>{
	// 注意这里得到的才是最终的数据
	console.log(ret)
})

2. GET请求方式的参数传递

方式1:

// client发送,从server端返回
fetch('/abc?id=123',{
	method:'GET'
}).then(data => {
	return data.text() // 返回一个Promise实例对象
}).then(ret=>{
	console.log(ret)
})
// server接收,并发送给client
app.get('/abc',(req,res)=>{
	res.send('传统的URL传递参数!' + req.query.id)
})

方式2:

// client发送,从server端返回
fetch('/abc/123',{
	method:'GET'
}).then(data => {
	return data.text() // 返回一个Promise实例对象
}).then(ret=>{
	console.log(ret)
})
// server接收,并发送给client
app.get('/abc/:id',(req,res)=>{
	res.send('Restful形式的URL传递参数!' + req.params.id)
})

3. DELETE请求方式的参数传递

// client发送,从server端返回
fetch('/abc/123',{
	method:'DELETE'
}).then(data => {
	return data.text() // 返回一个Promise实例对象
}).then(ret=>{
	console.log(ret)
})
// server接收,并发送给client
app.delete('/abc/:id',(req,res)=>{
	res.send('DELETE请求传递参数!' + req.params.id)
})

4. POST请求方式的参数传递

方式1(普通传参):

// client发送,从server端返回
fetch('/abc',{
	method:'POST',
	body:'uname=lisi&pwd=123',
	headers:{
		'Content-Type':'application/x-www-form-urlencoded'
	}
}).then(data => {
	return data.text() // 返回一个Promise实例对象
}).then(ret=>{
	console.log(ret)
})
const bodyParser = require('body-parser')

// server接收,并发送给client
app.post('/abc',(req,res)=>{
	res.send('POST请求传递参数!' + req.body.uname + '----' + req.body.pwd)
})

方式2(JSON传参):

// client发送,从server端返回
fetch('/abc',{
	method:'POST',
	body:JSON.stringify({
		uname: 'lisi',
		age:12
	}),
	headers:{
		'Content-Type':'application/json'
	}
}).then(data => {
	return data.text() // 返回一个Promise实例对象
}).then(ret=>{
	console.log(ret)
})
const bodyParser = require('body-parser')
const app = express()
app.use(bodyParser.json())

// server接收,并发送给client
app.post('/abc',(req,res)=>{
	res.send('POST请求传递参数!' + req.body.uname + '----' + req.body.pwd)
})

5. PUT请求方式的参数传递

// client发送,从server端返回
fetch('/abc/123',{
	method:'PUT',
	body:JSON.stringify({
		uname: 'lisi',
		age:12
	}),
	headers:{
		'Content-Type':'application/json'
	}
}).then(data => {
	return data.text() // 返回一个Promise实例对象
}).then(ret=>{
	console.log(ret)
})
const bodyParser = require('body-parser')
const app = express()
app.use(bodyParser.json())

// server接收,并发送给client
app.put('/abc/:id',(req,res)=>{
	res.send('PUT请求传递参数!' + req.params.id + '----' + req.body.uname + '----' + req.body.pwd)
})

3.4 fetch响应结果

响应数据格式

  • text():将返回体处理成字符串类型
  • json():返回结果和JSON.parse(responseText)一样
// client发送,从server端返回
fetch('/abc').then(data => {
	// return data.text()
	return data.json()
}).then(data=>{
	console.log(data) // JSON对象
	console.log(data.uname) // JSON对象.属性
})
// server接收,并发送给client
app.get('/abc',(req,res)=>{
	res.json({
		uname: 'lisi',
		age: 13,
		gender: 'male'
	})
})

附:字符串转JSON方法——var obj = JSON.parse(str)

4. 接口调用-axios用法

4.1 axios的基本特征

axios(官网:https://github.com/axios/axios)是一个基于Promise用于浏览器和node.js的HTTP客户端。

它具有以下特征:

  • 支持浏览器和node.js
  • 支持promise
  • 能拦截请求和响应
  • 自动转换JSON数据

4.2 axios的基本用法

项目安装Axios:
cnpm install axios --save

基本使用:

axios({
	url:'/adata',
	method:'GET' // 默认GET方法
}).then(ret=>{
		// data 属性名称是固定的,用于获取后台响应的实际数据
		console.log(ret.data)
	})

4.3 axios的常用API

  • get:查询数据
  • post:添加数据
  • put:修改数据
  • delete:删除数据

注:axios发送并发请求

  • 有时候,我们可能需要同时发送两个请求
    • 使用axios.all,可以放入多个请求的数组
    • axios.all([])返回的结果是一个数组 ,使用axios.spread可将数组[res1,res2]展开为res1,res2
// axios发送并发请求,两个请求同时相应之后才有结果
axios.all([axios({
  url:'/home/data1'
}), axios({
  url:'/home/data2'
})]).then(results=>{
	console.log(results) // 返回一个数组[res1,res2]
})

spread:

axios.all([axios({
  url:'/home/data1'
}), axios({
  url:'/home/data2'
})]).then(axios.spread((res1,res2) => {
	console.log(res1) // res1
	console.log(res2) // res2
}))

4.4 axios的参数传递

1. GET传递参数

  • 通过URL传递参数

方法1:

axios.get('/adata?id=123')
	.then(ret=>{
		console.log(ret.data) // axios get 传递参数123
	})
// server接收,并发送给client
app.get('/adata',(req,res)=>{
	res.send('axios get 传递参数' + req.query.id)
})

方法2:

axios.get('/adata/123')
	.then(ret=>{
		console.log(ret.data) // axios get (Restful) 传递参数123
	})
// server接收,并发送给client
app.get('/adata/:id',(req,res)=>{
	res.send('axios get (Restful) 传递参数' + req.params.id)
})
  • 通过params选项传递参数
axios.get('/adata',{
		params:{
			id:123
		}
	})
	.then(ret=>{
		console.log(ret.data) // axios get 传递参数123
	})
// server接收,并发送给client
app.get('/adata',(req,res)=>{
	res.send('axios get 传递参数' + req.query.id)
})

2. DELETE传递参数

  • 参数传递方式与GET类似

方法1:

axios.delete('/adata?id=123')
	.then(ret=>{
		console.log(ret.data)
	})

方法2:

axios.delete('/adata/123')
	.then(ret=>{
		console.log(ret.data)
	})

方法3:

axios.delete('/adata',{
		params:{
			id:123
		}
	})
	.then(ret=>{
		console.log(ret.data)
	})

3. POST传递参数

  • 通过选项传递参数(默认传递的是json格式的数据)
axios.post('/adata',{
		uname:'tom',
		pwd:123
	}).then(ret=>{
		console.log(ret.data)
})
// server接收,并发送给client
app.post('/adata',(req,res)=>{
	res.send('axios post 传递参数' + req.body.uname + req.body.pwd)
})
  • 通过URLSearchParams传递参数(application/x-www-form-urlencoded)
const params = new URLSearchParams();
params.append('uname','zhangsan');
params.append('pwd','111');

axios.post('/adata',params).then(ret=>{
	console.log(ret.data)
})
// server接收,并发送给client
app.post('/adata',(req,res)=>{
	res.send('axios post 传递参数' + req.body.uname + req.body.pwd)
})

4. PUT传递参数

  • 参数传递方式与POST类似
axios.put('/adata/123',{
		uname:'tom',
		pwd:123
	}).then(ret=>{
		console.log(ret.data)
})
// server接收,并发送给client
app.put('/adata/:id',(req,res)=>{
	res.send('axios post 传递参数' + req.params.id + req.body.uname + req.body.pwd)
})

4.5 axios 的响应结果

响应结果的主要属性

  • data:实际响应回来的数据
  • headers:响应头信息
  • status:响应状态码
  • statusText:响应状态信息

data为例:

axios.get('/adata')
	.then(ret=>{
		console.log(ret.data.uname) // lisi
	})
// server接收,并发送给client
app.post('/adata',(req,res)=>{
	res.json({
		uname:'lisi',
		age:12
	});
})

4.6 axios的全局配置

  • axios.defaults.timeout = 3000// 超时时间
  • axios.defaults.baseURL = 'http://localhost:3000/app'// 默认地址
  • axios.defaults.headers[' mytoken'] = 'aqwerwqwerqwere2ewe23eresdf23'// 设置请求头

配置请求的基准URL地址(默认地址):

axios.defaults.baseURL = 'http://localhost:3000/'
axios.get('adata') // 拼接成:http://localhost:3000/adata
	.then(ret=>{
		console.log(ret.data.uname) // lisi
	})

配置请求头信息:

axios.defaults.headers[' mytoken'] = 'aqwerwqwerqwere2ewe23eresdf23'

4.7 axios创建实例

  • 当我们从axios模块中导入对象时,使用的实例是默认的axios实例
  • 当给该实例设置一些默认配置时,这些配置就被固定下来了
  • 但是后续开发中,某些配置可能会不太一样。
  • 比如某些请求需要使用特定的baseURL或者timeout或者content-type等
  • 这个时候,我们就可以创建新的实例,并且传入属于该实例的配置信息
const instance1 = axios.create({
	baseURL: 'http://192.168.0.1:8000',
	timeout:5000
})
const instance2 = axios.create({
	baseURL: 'http://192.168.0.2:8000',
	timeout:8000
})

instance1({
	url:'/home/data1'
}).then(res=>{
	console.log(res)
})

4.8 axios拦截器

1. 请求拦截器

在请求发出之前设置一些信息,一般包括如下情况:

  • 比如config中的一些信息不符合服务器的要求
  • 比如每次发送网络请求时,都希望在界面中显示一个请求图标
  • 某些网络请求(比如登陆(token)),必须携带一些特殊信息
    在这里插入图片描述
axios.interceptors.request.use(function(config){
	// 在请求发出之前进行一些信息设置
	config.headers.mytoken = 'nihao';
	return config
},function(err){
	// 处理响应的错误信息
	console.log(err)
})

// axios.get().then...

2. 响应拦截器

在获取数据之前对数据做一些加工处理
在这里插入图片描述

axios.interceptors.response.use(function(res){
	// 在这里对返回的数据进行处理
	var data = res.data
	return data
},function(err){
	// 处理响应的错误信息
	console.log(err)
})

// axios.get().then...

4.9 axios的模块封装

对于不同组件调用axios时,需要在每个组件中引入axios的配置信息,一旦发生改变需要在每个组件中修改,非常麻烦。

因此最好的方式是引入一个全局Axios配置文件,并将公共部分封装起来,其他组件使用使直接引入即可。需要修改时(比如baseURL等信息),只需要修改这个全局配置文件即可,无需在每个组件中进行修改。

在src下新建一个名为network的文件夹,并在文件夹内新建一个名为request.js配置文件

request.js:

import axios from 'axios'

export function request(config) {
    // 1.创建axios实例
    const instance = axios.create({
        baseURL: 'http://192.168.0.1',
        timeout: 5000
    })

    // 2. axios的拦截器
    // 2.1 请求拦截器
    instance.interceptors.request.use(config => {
        // console.log(config); // 拦截请求信息,这块处理请求前的操作
        return config // 拦截之后必须得return出去,不然后台接收不到请求
    }, err => {
        console.log(err);
    })
    // 2.2 响应拦截器
    instance.interceptors.response.use(res => {
        // 这块处理响应前的操作
        return res.data
    },err => {
        console.log(err);
    })

    // 3.返回promise对象,在组件中执行then、catch等
    return instance(config)
}

组件中调用:

import { request } from '../network/request.js';

export default {
	name: '',
	data() {
		return {};
	},
	created() {
		// 封装request模块
		request({
			url: '/home/data'
		}).then(res => {
           // 成功时执行
           console.log(res);
		}).catch(err => {
           // 异常时执行
           console.log(err);
        });
	}
};

5. 接口调用-async/await用法

5.1 async/await的基本用法

  • async/await是ES7引入的新语法,可以更加方便的进行异步操作
  • async关键字用于函数上(async函数的返回值是Promise实例对象)
  • await关键字用于async函数当中(await可以得到异步的结果,也可以返回Promise对象

await返回Promise对象:

async function queryData(){
	const ret = await axios.get('/data')
	return ret.data
}

queryData().then(ret=>{
	console.log(ret)
})

await返回异步结果:

async function queryData(){
	var ret = await new Promise(function(resolve,reject){
		setTimeout(function(){
			resolve('nihao')
		},1000)
	})
	return ret
}

queryData().then(data=>{
	console.log(data) // nihao
})

5.2 async/await处理多个异步请求

多个异步请求的场景

axios.defaults.baseURL = 'http://localhost:3000'

async function queryData(){
	var info = await axios.get('data1')
	var ret = await axios.get('data2?info=' + info.data)
	return ret.data
}

queryData().then(data=>{
	console.log(data) // world
})
// server接收,并发送给client
app.get('/data1',(req,res)=>{
	res.send('hello');
})

app.get('/data2',(req,res)=>{
	if(req.query.info == 'hello'){
		res.send('world')
	}else{
		res.send('error')
	}
})

猜你喜欢

转载自blog.csdn.net/xiecheng1995/article/details/106295499
今日推荐