当前位置: 首页 > news >正文

JavaScript前后端交互-AJAX/fetch

摘自千峰教育kerwin的js教程

AJAX

1、AJAX 的优势

  1. 不需要插件的支持,原生 js 就可以使用
  2. 用户体验好(不需要刷新页面就可以更新数据)
  3. 减轻服务端和带宽的负担
  4. 缺点: 搜索引擎的支持度不够,因为数据都不在页面上,搜索引擎搜索不到

2、AJAX 的使用

  • 在 js 中有内置的构造函数来创建 ajax 对象
  • 创建 ajax 对象以后,我们就使用 ajax 对象的方法去发送请求和接受响应

3、AJAX发送请求

  1. 创建AJAX对象
  2. 配置连接信息(最好不要配置成同步)
  3. 发送
const xhr = new XMLHttpRequest();// xhr 对象中的 open 方法是来配置请求信息的
// 第一个参数是本次请求的请求方式 get / post / put / ...
// 第二个参数是本次请求的 url 
// 第三个参数是本次请求是否异步,默认 true 表示异步,false 表示同步
// xhr.open('请求方式', '请求地址', 是否异步)
xhr.open('get', './data.php')// 使用 xhr 对象中的 send 方法来发送请求
xhr.send()

4、AJAX接收响应

  • 发送完成后,我们就需要等待服务端的消息
  • 如果服务端正常的话,响应也能回到客户端
  • 但是我们拿不到响应
  • 如果想拿到响应,我们有两个前提条件
    1. 本次 HTTP 请求是成功的,也就是我们之前说的 http 状态码为 200 ~ 299
    2. ajax 对象也有自己的状态码,用来表示本次 ajax 请求中各个阶段
4.1、AJAX状态码
  • ajax 状态码 - xhr.readyState
  • 是用来表示一个 ajax 请求的全部过程中的某一个状态
    • readyState === 0: 表示未初始化完成,也就是 open 方法还没有执行
    • readyState === 1: 表示配置信息已经完成,也就是执行完 open 之后
    • readyState === 2: 表示 send 方法已经执行完成
    • readyState === 3: 表示正在解析响应内容
    • readyState === 4: 表示响应内容已经解析完毕,可以在客户端使用了
  • 这个时候我们就会发现,当一个 ajax 请求的全部过程中,只有当 readyState === 4 的时候,我们才可以正常使用服务端给我们的数据
  • 所以,配合 http 状态码为 200 ~ 299
    • 一个 ajax 对象中有一个成员叫做 xhr.status
    • 这个成员就是记录本次请求的 http 状态码的
  • 两个条件都满足的时候,才是本次请求正常完成
4.2、readyStateChange事件
  • 在 ajax 对象中有一个事件,叫做 readyStateChange 事件

  • 这个事件是专门用来监听 ajax 对象的 readyState 值改变的的行为

  • 也就是说只要 readyState 的值发生变化了,那么就会触发该事件(所以响应过程会触发多次)

  • 所以我们就在这个事件中来监听 ajax 的 readyState 是不是到 4 了

    const xhr = new XMLHttpRequest()
    xhr.open('get', './data.php')xhr.send()xhr.onreadyStateChange = function () {// 每次 readyState 改变的时候都会触发该事件// 我们就在这里判断 readyState 的值是不是到 4// 并且 http 的状态码是不是 200 ~ 299if (xhr.readyState === 4 && /^2\d{2}$/.test(xhr.status)) {// 这里表示验证通过// 我们就可以获取服务端给我们响应的内容了}
    }
    
4.3、onload事件
  • 相比于上述事件,这个只有在xhr.readyState === 4时才会触发
    xhr.onload = function () {if (xhr.status == 200) {} else of (xhr.status == 404) {}
    }
    
4.4、responseText响应体
  • ajax 对象中的 responseText 成员

  • 就是用来记录服务端给我们的响应体内容的

  • 所以我们就用这个成员来获取响应体内容就可以

    const xhr = new XMLHttpRequest()
    xhr.open('get', './data.php')xhr.send()xhr.onreadyStateChange = function () {if (xhr.readyState === 4 && /^2\d{2}$/.test(xhr.status)) {// 我们在这里直接打印 xhr.responseText 来查看服务端给我们返回的内容console.log(xhr.responseText)}
    }
    

5、发送post和get请求时如何携带参数

5.1、get请求携带参数
  • get 请求的参数就直接在 url 后面进行拼接就可以
    const xhr = new XMLHttpRequest()
    // 直接在地址后面加一个 ?,然后以 key=value 的形式传递
    // 两个数据之间以 & 分割
    xhr.open('get', './data.php?a=100&b=200')xhr.send()
    
    • 这样服务端就能接受到两个参数
    • 一个是 a,值是 100
    • 一个是 b,值是 200
5.2、 post请求携带参数
  • post 请求的参数是携带在请求体中的,所以不需要再 url 后面拼接
    const xhr = new XMLHttpRequest()
    xhr.open('get', './data.php')// 如果是用 ajax 对象发送 post 请求,必须要先设置一下请求头中的 content-type
    // 告诉一下服务端我给你的是一个什么样子的数据格式
    xhr.setRequestHeader('content-type', 'application/x-www-form-urlencoded')// 请求体直接再 send 的时候写在 () 里面就行
    // 不需要问号,直接就是 'key=value&key=value' 的形式
    xhr.send('a=100&b=200')
    
    • application/x-www-form-urlencoded 表示的数据格式就是 key=value&key=value

6、封装AJAX

  • 重点:要注意header和data的数据格式处理成对应的
function queryStringify(obj) {let str = ''for (let k in obj) str += `${k}=${obj[k]}&`return str.slice(0, -1)
}// 封装 ajax
function ajax(options) {let defaultoptions = {url: "",method: "GET",async: true,data: {},headers: {},success: function () { },error: function () { }}// 默认值合并,保证所有参数都有效let { url, method, async, data, headers, success, error } = {...defaultoptions,...options}// 当传的是对象,且设置header也是json时,将传的对象{key:value}转化为jsonif (typeof data === 'object' && headers["content-type"]?.indexOf("json") > -1) {data = JSON.stringify(data)}else {// 以下情况需要处理// 1. 传的是对象,但是header设置的xxx-form-urlencoded// 2. 传的直接就是表单(不设置的话默认是form编码) name=123&age=10data = queryStringify(data)}// 如果是 get 请求, 并且有参数, 那么直接组装一下 url 信息if (/^get$/i.test(method) && data) url += '?' + data// 4. 发送请求const xhr = new XMLHttpRequest()xhr.open(method, url, async)xhr.onload = function () {if (!/^2\d{2}$/.test(xhr.status)) {error(`错误状态码:${xhr.status}`)return }// 执行解析try {let result = JSON.parse(xhr.responseText)success(result)} catch (err) {error('解析失败 ! 因为后端返回的结果不是 json 格式字符串')}}// 设置请求头内的信息for (let k in headers) xhr.setRequestHeader(k, headers[k])if (/^get$/i.test(method)) {xhr.send()} else {xhr.send(data)}
}
ajax({url:"http://localhost:3000/users",method:"GET",async:true,// 这里header默认是form编码,但是传的对象,所以走else逻辑data:{username:"kerwin",password:"123"}, headers:{},success:function(res){console.log(res)},error:function(err){console.log(err)}
})

7、回调地狱

  • 当一个回调函数嵌套一个回调函数的时候

  • 就会出现一个嵌套结构

  • 当嵌套的多了就会出现回调地狱的情况

  • 比如我们发送三个 ajax 请求

    • 第一个正常发送

    • 第二个请求需要第一个请求的结果中的某一个值作为参数

    • 第三个请求需要第二个请求的结果中的某一个值作为参数

      ajax({url: '我是第一个请求',success (res) {// 现在发送第二个请求ajax({url: '我是第二个请求'data: { a: res.a, b: res.b },success (res2) {// 进行第三个请求ajax({url: '我是第三个请求',data: { a: res2.a, b: res2.b },success (res3) { console.log(res3) }})}})}
      })
      
      • 当代码成为这个结构以后,已经没有维护的可能了
      • 所以我们要把代码写的更加的艺术一些

8、promise

  • promise 是一个 ES6 的语法

  • 承诺的意思,是一个专门用来解决异步 回调地狱 的问题

  • 语法:

    new Promise(function (resolve, reject) {
    // resolve 表示成功的回调
    // reject 表示失败的回调
    }).then(function (res) {// 成功的函数
    }).catch(function (err) {// 失败的函数
    })
    
    • promise 就是一个语法

    • 我们的每一个异步事件,在执行的时候

    • 都会有三个状态,执行中 / 成功 / 失败

  • 因为它包含了成功的回调函数

  • 所以我们就可以使用 promise 来解决多个 ajax 发送的问题

    new Promise(function (resolve, reject) {ajax({url: '第一个请求',success (res) {resolve(res)}})
    }).then(function (res) {// 准备发送第二个请求return new Promise(function (resolve, reject) {ajax({url: '第二个请求',data: { a: res.a, b: res.b },success (res) {resolve(res)}})})
    }).then(function (res) {ajax({url: '第三个请求',data: { a: res.a, b: res.b },success (res) {console.log(res)}})
    })
    

9、 async/await

  • async/await 是一个 es7 的语法

  • 这个语法是 回调地狱的终极解决方案

  • 语法:

    async function fn() {const res = await promise对象
    }
    
  • 可以把异步代码写的看起来像同步代码

  • 只要是一个 promiser 对象,那么我们就可以使用 async/await 来书写

async function fn() {const res = await new Promise(function (resolve, reject) {ajax({url: '第一个地址',success (res) {resolve(res)}})})// res 就可以得到请求的结果const res2 = await new Promise(function (resolve, reject) {ajax({url: '第二个地址',data: { a: res.a, b: res.b },success (res) {resolve(res)}})})const res3 = await new Promise(function (resolve, reject) {ajax({url: '第三个地址',data: { a: res2.a, b: res2.b },success (res) {resolve(res)}})})// res3 就是我们要的结果console.log(res3)
}

这种方式如果要捕获错误,可以使用try-catch方式

fetch

XMLHttpRequest 是一个设计粗糙的 API,配置和调用方式非常混乱, 而且基于事件的异步模型写起来不友好。

兼容性不好 polyfill: https://github.com/camsong/fetch-ie8,所以还是推荐封装ajax

fetch("http://localhost:3000/users").then(res=>res.json()).then(res=>{console.log(res)})fetch("http://localhost:3000/users",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({username:"kerwin",password:"123"})}).then(res=>res.json()).then(res=>{console.log(res)})fetch("http://localhost:3000/users/5",{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({username:"kerwin",password:"456"})}).then(res=>res.json()).then(res=>{console.log(res)})fetch("http://localhost:3000/users/5",{method:"DELETE"}).then(res=>res.json()).then(res=>{console.log(res)})
//错误处理
fetch("http://localhost:3000/users1").then(res=>{if(res.ok){return res.json()}else{// 手动拒绝return Promise.reject({status:res.status,statusText:res.statusText})}}).then(res=>{console.log(res)}).catch(err=>{console.log(err)})

结语

我写过的基于React的项目中,一般会使用将axios(另个一将xhr封装的npm包)二次封装的方式,结合框架进行使用。

相关文章:

JavaScript前后端交互-AJAX/fetch

摘自千峰教育kerwin的js教程 AJAX 1、AJAX 的优势 不需要插件的支持,原生 js 就可以使用用户体验好(不需要刷新页面就可以更新数据)减轻服务端和带宽的负担缺点: 搜索引擎的支持度不够,因为数据都不在页面上&#xf…...

ZooKeeper单节点详细部署流程

ZooKeeper单节点详细部署流程 文章目录 ZooKeeper单节点详细部署流程 一.下载稳定版本**ZooKeeper**二进制安装包二.安装并启动**ZooKeeper**1.安装**ZooKeeper**2.配置并启动**ZooKeeper** ZooKeeper 版本与 JDK 兼容性3.检查启动状态4.配置环境变量 三.可视化工具管理**Zooke…...

流浪地球发动机启动问题解析与实现

目录 引言问题分析 2.1 发动机启动状态管理 2.2 手动启动与关联启动逻辑 2.3 最晚启动发动机的确定Python 实现 3.1 代码实现 3.2 <...

Java 注解使用教程

简介 Java 1.5 引入了注解&#xff0c;现在它在 Java EE 框架&#xff08;如 Hibernate、Jersey 和 Spring &#xff09;中被大量使用。Java 注释是该语言的一个强大特性&#xff0c;用于向 Java 代码中添加元数据。它们不直接影响程序逻辑&#xff0c;但可以由工具、库或框架…...

网络安全学习

博客目录 1.Ddos 攻击2.SYN Flood3.如何应对 Ddos 攻击4.Xss 漏洞5.越权访问漏洞6.水平越权与垂直越权7.水平越权8.垂直越权 1.Ddos 攻击 DDos 全名 Distributed Denial of Service&#xff0c;翻译成中文就是分布式拒绝服务。指的是处于不同位置的多个攻击者同时向一个或数个…...

4 前端前置技术(上):AJAX技术、Axios技术(前端发送请求)

文章目录 前言一、Ajax技术&#xff08;从服务端获取数据&#xff0c;发送各种请求&#xff09;0 接口文档管理&#xff1a;使用apipost等接口测试软件创建接口便于前端后端分离测试1 基本概念2 原生Ajax使用示例&#xff08;几年前的早期用法&#xff09; 二、 Axios技术(对原…...

2022年全国职业院校技能大赛网络系统管理赛项模块A:网络构建(样题3)-网络部分解析-附详细代码

目录 附录1:拓扑图 附录2:地址规划表 1.SW1 2.SW2 3.SW3 4.SW4 5.SW5 6.SW6 7.SW7 8.R1 9.R2 10.R3 11.AC1 12.AC2 13.AP2 14.AP3 15.EG1 16.EG2 附录1:拓扑图 附录2:地址规划表 设备...

ASP.NET Core中间件的概念及基本使用

什么是中间件 中间件是ASP.NET Core的核心组件&#xff0c;MVC框架、响应缓存、身份验证、CORS、Swagger等都是内置中间件。 广义上来讲&#xff1a;Tomcat、WebLogic、Redis、IIS&#xff1b;狭义上来讲&#xff0c;ASP.NET Core中的中间件指ASP.NET Core中的一个组件。中间件…...

每日Attention学习22——Inverted Residual RWKV

模块出处 [arXiv 25] [link] [code] RWKV-UNet: Improving UNet with Long-Range Cooperation for Effective Medical Image Segmentation 模块名称 Inverted Residual RWKV (IR-RWKV) 模块作用 用于vision的RWKV结构 模块结构 模块代码 注&#xff1a;cpp扩展请参考作者原…...

使用jmeter进行压力测试

使用jmeter进行压力测试 jmeter安装 官网安装包下载&#xff0c;选择二进制文件&#xff0c;解压。 tar -xzvf apache-jmeter-x.tgz依赖jdk安装。 yum install java-1.8.0-openjdk环境变量配置&#xff0c;修改/etc/profile文件&#xff0c;添加以下内容。 export JMETER/…...

LQB(0)-python-基础知识

一、Python开发环境与基础知识 python解释器&#xff1a;用于解释python代码 方式&#xff1a; 1.直接安装python解释器 2.安装Anaconda管理python环境 python开发环境&#xff1a;用于编写python代码 1.vscode 2.pycharm # 3.安装Anaconda后可以使用网页版的jupyter n…...

每日Attention学习18——Grouped Attention Gate

模块出处 [ICLR 25 Submission] [link] UltraLightUNet: Rethinking U-shaped Network with Multi-kernel Lightweight Convolutions for Medical Image Segmentation 模块名称 Grouped Attention Gate (GAG) 模块作用 轻量特征融合 模块结构 模块特点 特征融合前使用Group…...

QT 窗口A覆盖窗口B时,窗口B接受不到鼠标事件

一、问题 在项目的需求中&#xff0c;地图A上面需要叠放一个任务窗口B&#xff0c;B覆盖了A&#xff0c;导致A接受不到鼠标及滚轮事件。 二、解决方案 1、Qt::WA_TransparentForMouseEvents 是 Qt 框架中的一个属性&#xff0c;用于使指定的控件及其子控件不响应鼠标事件。当启…...

Unity安装教学与相关问题

文章目录 1. 前言2.Unity Hub2.1 下载Unity Hub2.2 安装Unity Hub2.3 注册Unity账号2.4 在Hub上登录账号2.5 在Hub上获取许可证 3. 下载并安装Unity3.1 从Unity Hub下载&#xff08;推荐&#xff09;3.1.1 选择下载版本3.1.2 选择下载组件3.1.3 安装Visual Studio Community 20…...

[Python人工智能] 四十九.PyTorch入门 (4)利用基础模块构建神经网络并实现分类预测

从本专栏开始,作者正式研究Python深度学习、神经网络及人工智能相关知识。前文讲解PyTorch构建回归神经网络。这篇文章将介绍如何利用PyTorch构建神经网络实现分类预测,其是使用基础模块构建。前面我们的Python人工智能主要以TensorFlow和Keras为主,而现在最主流的深度学习框…...

实现一个 LRU 风格的缓存类

实现一个缓存类 需求描述豆包解决思路&#xff1a;实现代码&#xff1a;优化11. std::list::remove 的时间复杂度问题2. 代码复用优化后的代码优化说明 优化21. 边界条件检查2. 异常处理3. 代码封装性4. 线程安全优化后的代码示例优化说明 DeepSeek&#xff08;深度思考R1&…...

【蓝桥杯嵌入式】4_key:单击+长按+双击

1、电路图 将4个按键的引脚设置为input&#xff0c;并将初始状态设置为Pull-up&#xff08;上拉输入&#xff09; 为解决按键抖动的问题&#xff0c;我们使用定时器中断进行消抖 打开TIM3时钟并设置参数&#xff0c;中断间隔10ms&#xff0c;当计数达到10000时溢出。80M/80/10…...

深入理解 C# 与.NET 框架

.NET学习资料 .NET学习资料 .NET学习资料 一、引言 在现代软件开发领域&#xff0c;C# 与.NET 框架是构建 Windows、Web、移动及云应用的强大工具。C# 作为一种面向对象的编程语言&#xff0c;而.NET 框架则是一个综合性的开发平台&#xff0c;它们紧密结合&#xff0c;为开…...

10. 神经网络(二.多层神经网络模型)

多层神经网络&#xff08;Multi-Layer Neural Network&#xff09;&#xff0c;也称为深度神经网络&#xff08;Deep Neural Network, DNN&#xff09;&#xff0c;是机器学习中一种重要的模型&#xff0c;能够通过多层次的非线性变换解决复杂的分类、回归和模式识别问题。以下…...

spark 性能调优 (一):执行计划

在 Spark 中&#xff0c;explain 函数用于提供数据框&#xff08;DataFrame&#xff09;或 SQL 查询的逻辑计划和物理执行计划的详细解释。它可以帮助开发者理解 Spark 是如何执行查询的&#xff0c;包括优化过程、转换步骤以及它将采用的物理执行策略。 1. 逻辑计划 (Logical…...

Arm Cortex-X2/X3架构解析与性能优化实践

1. Arm Cortex-X2/X3集群架构概述在Armv9架构的高性能计算领域&#xff0c;Cortex-X2和X3代表了当前最先进的CPU设计理念。作为DynamIQ共享单元(DSU)的核心组件&#xff0c;它们通过可配置的缓存层次结构和智能一致性协议&#xff0c;为现代异构计算提供了灵活的解决方案。1.1 …...

低多边形≠简陋!掌握这7个结构化Prompt技巧,3分钟产出可商用IP形象(附Figma网格对齐校验表)

更多请点击&#xff1a; https://intelliparadigm.com 第一章&#xff1a;低多边形设计的认知革命&#xff1a;从“简陋感”到“结构化美学” 低多边形&#xff08;Low-Poly&#xff09;设计曾长期被误读为建模能力不足的妥协产物&#xff0c;但其本质是一场对数字视觉语法的系…...

Deep Lake:AI数据湖实战指南,解决深度学习数据管理难题

1. 项目概述&#xff1a;当数据湖遇上深度学习如果你在深度学习项目里被数据管理搞得焦头烂额过&#xff0c;那你肯定懂我在说什么。模型训练到一半&#xff0c;发现数据版本不对&#xff0c;或者想对海量图像、视频做快速查询和采样&#xff0c;结果被IO速度卡得死死的。传统的…...

Mantic.sh:AI驱动的智能命令行工具,让自然语言生成终端命令

1. 项目概述&#xff1a;一个为开发者打造的智能终端伴侣 如果你和我一样&#xff0c;每天有超过一半的工作时间是在终端&#xff08;Terminal&#xff09;里度过的&#xff0c;那你一定对效率有着近乎偏执的追求。敲命令、查日志、管理进程、部署服务……这些重复且琐碎的操作…...

用STM32+LoRa+阿里云IoT Studio,我DIY了一个低成本畜牧电子围栏(附完整代码)

基于STM32与LoRa的智能畜牧围栏系统开发实战 在广袤的牧区&#xff0c;牲畜走失一直是困扰牧民的核心问题。传统物理围栏不仅成本高昂&#xff0c;在草原这类开放地形中实施难度也很大。本文将详细介绍如何利用STM32微控制器、LoRa远距离通信模块和阿里云IoT Studio平台&#x…...

从零打造专业GitHub个人资料页:Markdown与动态集成实战指南

1. 项目概述与核心价值 在技术圈子里混了十几年&#xff0c;我越来越觉得&#xff0c;一个开发者的“数字门面”和代码能力同等重要。这个门面&#xff0c;很多时候就是你的GitHub主页。早些年&#xff0c;大家的GitHub个人页面就是个简单的仓库列表&#xff0c;加上一些贡献图…...

DIY蓝牙游戏手柄:基于Bluefruit EZ-Key的免编程硬件制作全攻略

1. 项目概述与设计思路几年前&#xff0c;我还在用有线手柄在电脑上打游戏&#xff0c;那根线总是缠来缠去&#xff0c;桌面也乱糟糟的。后来市面上无线手柄选择多了&#xff0c;但总感觉少了点自己动手的乐趣&#xff0c;功能也千篇一律。直到我开始接触像Adafruit Bluefruit …...

蜘蛛池技术解析:网站收录提速的关键工具与运营策略

在搜索引擎优化领域&#xff0c;蜘蛛池是助力网站收录提速的重要辅助工具&#xff0c;尤其适配新站、低权重站或海量内容站&#xff0c;能有效破解收录慢、收录少、深层页面难抓取等痛点。本文从技术原理、核心价值、搭建要点及合规运营策略四方面&#xff0c;全面解析蜘蛛池的…...

Flutter桌面端窗口控制:从隐藏标题栏到自定义全屏交互

1. 为什么需要自定义窗口控制&#xff1f; 当你用Flutter开发Windows桌面应用时&#xff0c;系统默认的标题栏和窗口样式往往显得格格不入。想象一下&#xff0c;你精心设计了一套深色主题的UI&#xff0c;结果顶部突然冒出一条灰白色的标准标题栏——就像给西装革履的绅士戴了…...

从单体智能到组织智能:AgentOrg多智能体系统架构与实战

1. 项目概述&#xff1a;从单体智能到组织智能的范式跃迁最近在AI Agent领域&#xff0c;一个名为“AgentOrg”的开源项目引起了我的注意。这个由Angelopvtac发起的项目&#xff0c;其核心思想非常吸引人&#xff1a;它不再将AI Agent视为一个孤立的、执行单一任务的智能体&…...