Vue2 基础四前后端交互

devtools/2024/9/23 13:35:51/

VueActual">代码下载

前后端交互模式

接口调用方式:原生ajax、基于jQuery的ajax、fetchaxios

URL__6">URL 地址格式

传统形式的 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),用于定位页面的某个位置

Restful 形式的 URL HTTP请求方式:GET 查询、POST 添加、PUT 修改、DELETE 删除。

Promise_19">Promise

官网地址

JavaScript的执行环境是单线程,常见的异步调用:定时任务、ajax、事件函数。多次异步调用的结果顺序不确定,异步调用结果如果存在依赖需要嵌套。

                    // 定时任务let v = 1;setTimeout(() => {v = 2;}, 1000);console.log('v: ', v);// 多次异步调用$.get('http:localhost/data1', function(data) {console.log('data: ', data);});$.get('http:localhost/data2', function(data) {console.log('data: ', data);});$.get('http:localhost/data3', function(data) {console.log('data: ', data);});// 嵌套调用$.get('http:localhost/data1', function(data) {console.log('data: ', data);$.get('http:localhost/data2', function(data) {console.log('data: ', data);$.get('http:localhost/data3', function(data) {console.log('data: ', data);});});});

Promise 是异步编程的一种解决方案,从语法上讲,Promise是一个对象,从它可以获取异步操作的消息。使用 Promise 主要有以下好处:

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

Promise__58">Promise 基本用法

实例化 Promise 对象,构造函数中传递函数,该函数用于处理异步任务,resolve 和 reject 两个参数用于处理成功和失败两种情况,并通过 p.then 获取处理结果:

 var p = new Promise(function(resolve, reject){// 成功时调用 resolve()// 失败时调用 reject()});p.then(funciton(ret){// 从resolve得到正常结果}, function(ret){// 从reject得到错误信息});let p = new Promise(function(resolve, reject) {setTimeout(() => {let f = true;if (f) {resolve('正常');} else {reject('出错啦');}}, 1000);
});
p.then(function(data) {console.log('data: ', data);
}, function(info) {console.log('info: ', info);
});

PromiseAjax_90">基于Promise处理Ajax请求

处理原生Ajax:

                    let p = new Promise(function(resolve, reject) {let xhr = new XMLHttpRequest();xhr.open('GET', 'http:localhost/data1');xhr.send();xhr.onreadystatechange = function() {if (xhr.readyState === 4) {if (xhr.status === 200) {resolve(xhr.responseText);} else {reject('出错啦');}}};});p.then(function(data) {console.log('data: ', data);}, function(info) {console.log('info: ', info);})

发送多次ajax请求:

                    function queryData(url) {let p = new Promise(function(resolve, reject) {let xhr = new XMLHttpRequest();xhr.open('GET', url);xhr.send();xhr.onreadystatechange = function() {if (xhr.readyState === 4) {if (xhr.status === 200) {resolve(xhr.responseText);} else {reject('出错啦');}}};});return p;}queryData('http:localhost/data1').then(function(data) {console.log('data: ', data);return queryData('http:localhost/data2');}).then(function(data) {console.log('data: ', data);return queryData('http:localhost/data3');}).then(function(data) {console.log('data: ', data);});

then参数中的函数返回值:

  • 返回 Promise 实例对象,返回的该实例对象会调用下一个 then
  • 返回普通值,返回的普通值会直接传递给下一个 then,通过 then 参数中的第一个函数的参数接收该值
                    function createPromise(flag) {let q = new Promise(function(resolve, reject) {setTimeout(() => {if (flag) {resolve('成功');} else {reject('失败');}}, 1000);});return q;}createPromise(false).then(function(data) {console.log('data: ', data);return data;}, function(info) {console.log('info: ', info);return info;}).then(function(data) {console.log('--data: ', data, '--');}, function(info) {console.log('--info: ', info, '--');})// 打印结果// info:  失败// --data:  失败 --

PromiseAPI_177">Promise常用的API

  • p.then() 得到异步任务的正确结果,也可以得到异步任务的正确结果和异常信息。
  • p.catch() 获取异常信息。
  • p.finally() 成功与否都会执行(尚且不是正式标准)。
  • Promise.all() 接受一个数组作参数,数组中的对象均为promise实例(如果不是一个 promise,该项会被用 Promise.resolve 转换为一个promise)。并发处理多个异步任务,所有任务都执行完成才能得到结果(全部任务成功才算成功,只要有一个任务异常就只能得到此任务的异常信息)。
  • Promise.race() 方法同样接受一个数组作参数。并发处理多个异步任务,只要有一个任务完成就能得到结果。
                    function queryData(flag, index) {let p = new Promise(function(resolve, reject) {setTimeout(() => {if (flag) {resolve('成功-' + index);} else {reject('失败-' + index);}}, 1000);});return p;}queryData(true, 1).then(function(data){console.log('then success data: ', data);}).catch(function(info) {console.log('catch info: ', info);}).finally(function() {console.log('finally');});// 打印结果:// then success data:  成功-1// finallyqueryData(false, 2).then(function(data){console.log('then success data: ', data);}).catch(function(info) {console.log('catch info: ', info);}).finally(function() {console.log('finally');});// 打印结果:// catch info:  失败-2// finallyPromise.all([queryData(true, 3), queryData(false, 4), queryData(false, 5)]).then(function(result) {console.log('result: ', result);}, function(info) {console.log('error: ', info);});// 打印结果:// error:  失败-4Promise.race([queryData(true, 6), queryData(false, 7), queryData(true, 8)]).then(function(result) {console.log('result: ', result);}, function(info) {console.log('error: ', info);});// 打印结果:// result:  成功-6

fetch_236">fetch

官网地址

  • Fetch API是新的ajax解决方案,更加简单地获取数据,功能更强大、更灵活。
  • 语法结构 fetch(url, options).then(fn1).then(fn1).catch(fn2),Fetch会返回Promise,所以我们可以使用 then 拿到请求成功的结果。
  • fetch不是ajax的进一步封装,而是原生js,基于Promise实现,没有使用XMLHttpRequest对象。
                    fetch('http://localhost/data1').then(function(response) {// response 是响应体console.log('response: ', response);// text()方法属于fetchAPI的一部分,它返回一个Promise实例对象,用于获取后台返回的数据let r = response.text();console.log('text: ', r);return r;}).then(function(data) {// 这里得到的才是最终数据console.log('data: ', data);});// 打印结果:// response:  Response {type: 'cors', url: 'http://localhost/data1', redirected: false, status: 200, ok: true, …}// text:  Promise {[[PromiseState]]: 'pending', [[PromiseResult]]: undefined}// data:  data1

fetch 请求参数,常用配置选项:

  • method(String): HTTP请求方法,默认为GET (GET、POST、PUT、DELETE)
  • body(String): HTTP的请求参数
  • headers(Object): HTTP的请求头,默认为{}

fetch 响应数据格式:

  • text():将返回体处理成字符串类型
  • json():返回结果和 JSON.parse(responseText)一样
                    // getfetch('http://localhost/fdata?id=1').then(function(res) {return res.text();}).then(function(data) {console.log('data: ', data);});// get 动态参数fetch('http://localhost/fdata/2', {method: 'get'}).then(function(res) {return res.text();}).then(function(data) {console.log('data: ', data);});// post url-encoded 参数fetch('http://localhost/fdata', {method: 'post',body: 'uname=张三&password=123456',headers: {'Content-Type': 'application/x-www-form-urlencoded'}}).then(function(res) {return res.text();}).then(function(data) {console.log('data: ', data);});// post josn 参数fetch('http://localhost/fdata', {method: 'post',body: JSON.stringify({uname: '李四',password: '123456'}),headers: {'Content-Type': 'application/json'}}).then(function(res) {return res.json();}).then(function(data) {console.log('data: ', data);});// deletefetch('http://localhost/fdata/3', {method: 'delete'}).then(function(res) {return res.text();}).then(function(data) {console.log('data: ', data);});// putfetch('http://localhost/fdata/4', {method: 'put',body: JSON.stringify({uname: '王五',password: '123456'}),headers: {'Content-Type': 'application/json'}}).then(function(res) {return res.json();}).then(function(data) {console.log('data: ', data);});

axios_341">axios

axios(官网)是一个基于Promise 用于浏览器和 node.js 的 HTTP 客户端。它具有以下特征:

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

基本用法:

axios.get(‘/adata').then(ret=>{// data属性名称是固定的,用于获取后台响应的数据console.log(ret.data)})

axios 的响应结果的主要属性:

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

axios 的参数传递:

                    // getaxios.get('http://localhost/data?id=1').then(function(res) {console.log(res.data);});// get 动态参数axios.get('http://localhost/data/2').then(function(res) {console.log(res.data);});// get params 形式参数axios.get('http://localhost/data', {params: {id: 3}}).then(function(res) {console.log(res.data);});// post 通过 URLSearchParams 传递url-encoded参数let params = new URLSearchParams();params.append('uname', '张三');params.append('password', '123');console.log(params);axios.post('http://localhost/data', params).then(function(res) {console.log(res.data);});// post json参数axios.post('http://localhost/data', {uname: '李四',password: '123'}).then(function(res) {console.log(res.data);});// delete 与 get 类似axios.delete('http://localhost/data?id=4').then(function(res) {console.log(res.data);});axios.delete('http://localhost/data/5').then(function(res) {console.log(res.data);});axios.delete('http://localhost/data', {params: {id: 6}}).then(function(res) {console.log(res.data);});// put 与 post 类似axios.put('http://localhost/data/7', {uname: '王五',password: '123'}).then(function(res) {console.log(res.data);});

axios 还可以如此传递参数:

axios({method: '请求类型',url: '请求的URL地址', data: { /* POST数据 */ },params: { /* GET参数 */ }
}).then(callback)

axios 的全局配置:

  • axios.defaults.timeout = 3000; // 超时时间
  • axios.defaults.baseURL = ‘http://localhost:3000’; // 默认地址
  • axios.defaults.headers[‘mytoken’] = ‘aqwerwqwerqwer2ewrwe23eresdf23’; //设置请求头
  • axios.defaults.headers.common[‘Authorization’] = AUTH_TOKEN;
  • axios.defaults.headers.post[‘Content-Type’] = ‘application/x-www-form-urlencoded’; // 配置公共的 post 的 Content-Type
                    axios.defaults.baseURL = 'http://localhost';axios.defaults.headers['mytoken'] = 'zhaoliu';axios.get('data-json').then(function(res) {console.log(res.data);});

axios__454">axios 拦截器

  • 请求拦截器:请求拦截器的作用是在请求发送前进行一些操作,例如在每个请求体里加上token,统一做了处理如果以后要改也非常容易
  • 响应拦截器:响应拦截器的作用是在接收到响应后进行一些操作,例如在服务器返回登录状态失效,需要重新登录的时候,跳转到登录页
                    axios.interceptors.request.use(function(config) {console.log('config: ', config);console.log('url: ', config.url);if (config.url.indexOf('/data-json1') !== -1) {config.headers.mytoken = 'xxxx';}return config});axios.interceptors.response.use(function(res) {console.log('response: ', res);if (res.request.responseURL.indexOf('/data-json1') !== -1) {return res.data;}return res;}, function(err) {console.log('err: ', err);});axios.get('http://localhost/data-json1').then(function(res) {console.log('data: ', res);});

asyncawait_482">接口调用-async/await用法

async/await是ES7引入的新语法,它的实现是基于Promise,可以更加方便的进行异步操作:

  • async 关键字用于函数上(任何一个 async 函数都会隐式返回一个 promise)
  • await 关键字用于 async 函数当中,await函数不能单独使用(await可以得到异步的结果,也可以直接跟一个 Promise实例对象)
                    async function queryData() {var ret = await axios.get('http://localhost/data/1')return ret.data;}queryData().then(function(data) {console.log('data: ', data);});async function queryData() {var ret = await new Promise(function(resolve, reject){setTimeout(() => {resolve('100');}, 1000);});return ret;}queryData().then(function(res) {console.log('res: ', res);});

async/await 让异步代码看起来、表现起来更像同步代码,多个异步请求的场景:

                    async function queryData() {var info = await axios.get('http://localhost/data/1');var ret = await axios.get('http://localhost/data?id=' + info.data.id);return ret.data;}queryData().then(function(data) {console.log('data: ', data);})

综合案例——(基于后台接口的图书管理案例)

axios 全局配置以及配置响应拦截器:

        // 全局配置 默认地址axios.defaults.baseURL = 'http://localhost:80/';// 响应拦截器axios.interceptors.response.use(function(res) {return res.data;});

加载图书列表

使用 asyncawait 封装 queryData 函数获取后台数据:

                queryData: async function() {this.books = await axios.get('books')}

删除 mounted 钩子函数中的假数据,调用获取后台接口数据的函数 queryData:

            mounted: function() {// 该生命周期钩子函数被触发的时候,模板已经可以使用// 一般此时用于获取后台数据,然后把数据填充到模板this.queryData();}

其他功能实现

验证图书名是否可用:

            watch: {bname: async function(n) {if (n.length > 0) {let ret = await axios.get('books/check/' + n);console.log('ret: ', ret);this.confirm = !ret.status;} else {this.confirm = false;}}}

去编辑图书:

                editHandle: async function(m) {let ret = await axios.get('books/' + m.id);if (ret !== null) {this.bid = ret.id;this.bname = ret.name;this.flag = false;}}

添加、编辑图书:

                addHandle: async function() {console.log('addHandle');if (this.flag) { // 添加let ret = await axios.post('books', {name: this.bname})// 成功重新加载数据if (ret.code == 200) {this.queryData();}} else { // 编辑let ret = await axios.put('books', {id: this.bid,name: this.bname});// 成功重新加载数据if (ret.code == 200) {this.queryData();}this.flag = true;}this.bid = '';this.bname = '';}

删除图书:

                deleteHandle: async function(m) {let ret = await axios.delete('books/' + m.id);// 成功重新加载数据if (ret.code == 200) {this.queryData();}}

图书管理后台实现

新建后台项目文件夹 books, 安装 express、cros 这两个包。

新建 handle.js 文件处理接口:

// 处理文件
const path = require('path');
const fs = require('fs');
const data = require('./data.json');// 生成图书id
function generateBookId() {return Math.max.apply(null, data.map(function(v) {return v.id;})) + 1;
}
// 写入数据
function writeData(res) {fs.writeFile(path.join(__dirname, 'data.json'), JSON.stringify(data), function(err) {if (err) {res.json({code: 500,err: err});} else {res.json({code: 200,msg: '成功'});}})
}
// 获取图书
function books(req, res) {res.send(data);
}
// 添加图书
function addBook(req, res) {const body = req.body;const book = {id: generateBookId(),name: body.name,date: + new Date()};console.log('book: ', book);data.unshift(book);writeData(res);
}
// 获取单个图书
function oneBook(req, res) {console.log('params: ', req.params);const id = req.params.id;let book = null;data.some(function(v, i, a) {console.log('v: ', v);if (v.id == id) {book = v;return true;}});console.log('book: ', book);res.json(book);
}
// 编辑图书
function editBook(req, res) {const body = req.body;console.log('body: ', body);data.some(function(v, i, a) {if (body.id == v.id) {v.name = body.name;}});writeData(res);
}
// 删除图书
function deleteBook(req, res) {console.log('params: ', req.params);const id = req.params.id;data.some((v, i, a) => {if (v.id == id) {data.splice(i, 1);}});writeData(res);
}
// 验证图书名是否存在
function checkName(req, res) {const name = req.params.name;let result = false;data.some(function(v, i, a) {result = name == v.name;return result;});res.json({status: result});
}module.exports = {books,addBook,oneBook,editBook,deleteBook,checkName
}

新建 router.js 文件,处理路由:

// 路由模块
let express = require('express');
let router = express.Router();
let handle = require('./handle');// 获取图书
router.get('/books', handle.books);// 添加图书
router.post('/books', handle.addBook);// 获取单个图书
router.get('/books/:id', handle.oneBook);// 编辑图书
router.put('/books', handle.editBook);// 删除图书
router.delete('/books/:id', handle.deleteBook);// 验证图书名是否存在
router.get('/books/check/:name', handle.checkName);module.exports = router;

新建 index.js 文件,处理服务:

// 导入 express
const express = require('express');// 创建服务器
const app = express();// 配置 cors 跨域中间件
const cors = require('cors');
app.use(cors());
// 配置解析 application/x-www-form-urlencoded 格式的表单数据的中间件
app.use(express.urlencoded({ extended: false }));
// 配置解析表单中的 JSON 格式的数据的中间件
app.use(express.json());// 启动静态资源服务
app.use(express.static('public'))// 配置路由
let router = require('./router');
app.use(router);// 指定端口,启动服务器
app.listen(80, function(){console.log('server running at http://127.0.0.1:80');
});

附录

附录一

示例 node 后台代码:

// 导入模块
const express = require('express');
// 创建服务器
const app = express();// 配置跨域中间件
app.use(function(req, res, next) {res.header("Access-Control-Allow-Origin", "*");res.header('Access-Control-Allow-Methods', 'PUT, GET, POST, DELETE, OPTIONS');res.header('Access-Control-Allow-Headers', 'Content-Type');next();
});
// 配置自定义请求头
app.use('/data-json', function(req, res, next) {res.header('Access-Control-Allow-Headers', 'mytoken');next();
});
app.use('/data-json1', function(req, res, next) {res.header('Access-Control-Allow-Headers', 'mytoken');next();
});// 配置数据解析中间件
app.use(express.json());
app.use(express.urlencoded({ extended: false }));// 监听请求
app.get('/data1', function(req, res) {console.log('----data1----');res.send('data1');
});
app.get('/data2', function(req, res) {console.log('----data2----');res.send('data2');
});
app.get('/data3', function(req, res) {console.log('----data3----');res.send('data3');
});app.get('/data', function(req, res) {console.log(req.query);res.send({method: 'get',...req.query});
});
app.get('/data/:id', function(req, res) {console.log(req.params);res.send({method: 'get',...req.params});
});
app.post('/data', function(req, res) {console.log(req.body);res.send({method: 'post',...req.body});
});
app.delete('/data', function(req, res) {console.log(req.params);res.send({method: 'delete',...req.query});
});
app.delete('/data/:id', function(req, res) {console.log(req.params);res.send({method: 'delete',...req.params});
});
app.put('/data/:id', function(req, res) {console.log(req.params);console.log(req.body);res.send({method: 'put',id: req.params.id,...req.body});
});app.get('/data-json', (req, res) => {console.log(req.headers);res.json({uname: '赵六',age: 12});
});
app.get('/data-json1', (req, res) => {console.log(req.headers);res.json({uname: '赵六',age: 12});
});// 调用 app.listen(端口号, 启动成功后的回调函数),启动服务器
app.listen(80, function() {console.log('server running at http://127.0.0.1:80');
});

http://www.ppmy.cn/devtools/8845.html

相关文章

完成学校官网页面制作

<!DOCTYPE html> <html lang"en"> <head> <meta charset"UTF-8"> <title>教务系统</title> <style> .wap{ margin:0 auto; width:955px; } .top{ height:150px; padding-left:85px; …

软件测试金三银四招聘季,好公司10大特点VS烂公司10大特点

选择公司&#xff0c;就是在选自己未来的命运。 遇到一家好公司&#xff0c;你未来的职业道路&#xff0c;生活水平&#xff0c;工作热情&#xff0c;技术提升都是积极生长的。 但遇到一家烂公司&#xff0c;你未来的一年甚至几年&#xff0c;都将处在水深火热之中。 有时候仅仅…

FFmpeg合并音视频文件操作备忘(mac版)

利用NDM嗅探插件从B站下载下来的文件是音视频分开的&#xff0c;用剪辑软件合并时发现导出时文件都特别大&#xff0c;于是使用FFmpeg处理 环境&#xff1a; MBP M1芯片版 系统 macOS Sonama 14.4.1 操作步骤&#xff1a; 一、官方下载链接&#xff1a;https://evermeet.cx/…

使用SpringBoot3+Vue3开发公寓管理系统

项目介绍 公寓管理系统可以帮助公寓管理员更方便的进行管理房屋。功能包括系统管理、房间管理、租户管理、收租管理、房间家具管理、家具管理、维修管理、维修师傅管理、退房管理。 功能介绍 系统管理 用户管理 对系统管理员进行管理&#xff0c;新增管理员&#xff0c;修改…

Pytorch实用教程:nn.Linear内部是如何实现的,从哪里可以看到源码?

文章目录 nn.Linear简介nn.Linear 基本介绍nn.Linear 的参数 nn.Linear源码解析查看源码的方法nn.Linear 的核心源码 nn.Linear用法的示例代码示例说明示例代码代码解释 nn.Linear简介 nn.Linear 是 PyTorch 中非常基础的一个模块&#xff0c;用于实现全连接层。下面我会详细解…

mars3d实现禁止地图移动,禁止地图左右平移,但是鼠标可以移动的效果。

new mars3d.layer.GeoJsonLayer({渲染后实现鼠标左键按住不释放拖动时&#xff0c;地图不跟着拖动效果 当前问题&#xff1a; 1.在map初始化&#xff0c;或者是加载效果的时候&#xff0c;整个地球的场景都是一样的。 如果鼠标左键按住不释放&#xff0c;在屏幕上拖动的时候…

ESLlint重大更新后,使用旧版ESLint搭配Prettier的配置方式

概要 就在前几天&#xff0c;ESLint迎来了一次重大更新&#xff0c;9.0.0版本&#xff0c;根据官方文档介绍&#xff0c;使用新版的先决条件是Node.js版本必须是18.18.0、20.9.0&#xff0c;或者是>21.1.0的版本&#xff0c;新版ESLint将不再直接支持以下旧版配置(非扁平化…

[Flutter3] 记录Dio的简单封装(一)

文章目录 效果使用ResponseEntity类DioManager封装_onResponse / _onDioException 的设计Response的处理catch处理 效果 请求成功/失败/异常的日志输出效果 成功: 失败:500 失败:404 网络异常: 使用 举个使用的例子, 在调用 DioManager的时候, 直接通过返回值的状态, 来…