AJAX 入门笔记

课程地址

AJAX = Asynchronous JavaScript and XML(异步的 JavaScript 和 XML)
AJAX 不是新的编程语言,而是一种使用现有标准的新方法
AJAX 最大的优点是在不重新加载整个页面的情况下,可以与服务器交换数据并更新部分网页内容
XMLHttpRequest 只是实现 Ajax 的一种方式。

XML

可扩展标记语言,用来存储和传输数据(序列化),其于 HTML 类似,但是 XML 中的标签不是预定义的,而是自定义的

var s1 = {name: "daniel",age: 18,gender: "M"
}

用 XML 表示为:

<student><name>daniel</name><age>18</age><gender>M</gender>
</student>

现在基本被 json 代替:

{"name": "daniel","age": "18","gender": "M"
}	

AJAX 的优缺点

优点

  • 可以不刷新页面与服务器进行通信
  • 允许根据用户事件更新部分页面内容

缺点

  • 没有浏览历史,不能回退
  • 存在跨域问题
  • SEO 不友好

HTTP 报文格式

post 请求:
在这里插入图片描述
响应:
在这里插入图片描述

express

npm init --yes	# 初始化工程
npm install express		# 安装 express

AJAX 发送 GET 请求

服务端代码如下:

const express = require('express');
const app = express();app.get('/server', (request, response) => {// 允许跨域response.setHeader('Access-Control-Allow-Origin', '*');response.send('hello, world');
});app.listen(8000, () => {console.log("listening on 8000");
})

前端代码如下:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><style>#result{width: 200px;height: 100px;border: solid 2px red;}</style>
</head>
<body><button>发送请求</button><div id="result"></div>
</body>
<script>const btn0 = document.getElementsByTagName('button')[0];btn0.onclick = function() {// 1. 创建对象const xhr = new XMLHttpRequest();const result = document.getElementById('result')// 2. 初始化xhr.open('GET', 'http://127.0.0.1:8000/server');// 3. 发送xhr.send();/* 4. 事件绑定,处理服务端返回的结果。state 有如下 5 个值:0:未初始化1:open 方法调用完毕2:send 方法调用完毕3:服务端返回了部分结果4:服务端返回了全部结果*/xhr.onreadystatechange = function() {if (xhr.readyState === 4) { // 服务端返回了所有结果if (xhr.status >= 200 && xhr.status < 300) {result.innerHTML = xhr.response;}}}}
</script>
</html>

GET 设置请求参数

查询字符串参数以 ? 开始,以 & 分隔:

 xhr.open('GET', 'http://127.0.0.1:8000/server?a=100&b=200&c=300');

AJAX 发送 POST 请求

服务端添加处理 post 请求的回调函数:

app.post('/server', (request, response) => {response.setHeader('Access-Control-Allow-Origin', '*');response.send('hello, post');
});

前端:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<style>#result {width: 200px;height: 100px;border: solid 2px red;}
</style>
<body><div id="result"></div>
</body>
<script>const result = document.getElementById('result');result.addEventListener('mouseover', function() {// console.log('mouseover');const xhr = new XMLHttpRequest();xhr.open('POST', 'http://localhost:8000/server');xhr.send();xhr.onreadystatechange = function() {if (xhr.readyState == 4) {if (xhr.status >= 200 && xhr.status < 300) {result.innerHTML = xhr.response;}}};});
</script>
</html>

POST 设置请求体

xhr.send('a=100&b=200&c=300');
xhr.send('a:100&b:200&c:300');

设置请求头信息

一般将身份参数信息放入请求头

xhr.setRequestHeader('Content-Type', 'application/x-www-from-urlencoded');
xhr.setRequestHeader('name', 'application/x-www-from-urlencoded');

服务端代码加入:

app.all('/server', (request, response) => {response.setHeader('Access-Control-Allow-Origin', '*');response.setHeader('Access-Control-Allow-Headers', '*');	// 允许所有请求头response.send('hello, post');
});

服务端响应 JSON 数据

服务端返回一个 json 字符串

app.all('/json-server', (request, response) => {response.setHeader('Access-Control-Allow-Origin', '*');response.setHeader('Access-Control-Allow-Headers', '*');const data = {name: 'daniel'};response.send(JSON.stringify(data));	// 序列化
});

客户端从 json 字符串中解析出 json 对象:

<script>const result = document.getElementById('result');window.onkeydown = function() {const xhr = new XMLHttpRequest();xhr.open('GET', 'http://localhost:8000/json-server');xhr.send();xhr.onreadystatechange = function() {if (xhr.readyState === 4) {if (xhr.status >= 200 && xhr.status < 300) {//result.innerHTML = xhr.response;let data = JSON.parse(xhr.response);	// 反序列化result.innerHTML = data.name;}}}}
</script>

安装 nodemon,在修改服务端代码后能够自动重启 nodejs

npm install -g nodemon

使用 nodemon 启动 nodejs:

nodemon server.js

ie 缓存问题:ie 会缓存 ajax 的请求结果,如果服务端修改了响应内容,ie 不能及时地呈现。解决方法:在请求后面加上时间戳参数,使得每次请求内容都不同

请求超时与网络异常

对 ajax 做超时设置,给用户提醒

服务端设置延时发送响应:

app.all('/timeout', (request, response) => {response.setHeader('Access-Control-Allow-Origin', '*');setTimeout(() => {  // 延时发送response.send('hello, timeout 3s');}, 3000);
});

前端代码添加超时和网络异常处理:

<script>const btn = document.getElementsByTagName('button')[0];const result = document.getElementById('result');btn.addEventListener('click', function() {// console.log('mouseover');const xhr = new XMLHttpRequest();xhr.timeout = 2000;		// 给 ajax 设置超时xhr.ontimeout = () => { // 超时回调alert("timeout!!!");}xhr.onerror = () => {   // 网络异常回调alert("bad network!!!");}xhr.open('POST', 'http://localhost:8000/timeout');xhr.send();xhr.onreadystatechange = function() {if (xhr.readyState == 4) {if (xhr.status >= 200 && xhr.status < 300) {result.innerHTML = xhr.response;}}};});
</script>

取消请求

使用 abort() 方法即可:

<body><button>点击发送请求</button><button>点击取消请求</button>
</body>
<script>const btn1 = document.getElementsByTagName('button')[0];const btn2 = document.getElementsByTagName('button')[1];let xhr = null;btn1.onclick = function() {xhr = new XMLHttpRequest();xhr.open('GET', 'http://localhost:8000/timeout');xhr.send();xhr.onreadystatechange = function() {if (xhr.readyState == 4) {if (xhr.status >= 200 && xhr.status < 300) {console.log(xhr.response);}}};};btn2.onclick = function () {xhr.abort();}
</script>

重复发送请求问题

设置标志变量,判断是否重复发送:

<script>const btn0 = document.getElementsByTagName('button')[0];const btn1 = document.getElementsByTagName('button')[1];let xhr = null;let isSending = false;btn0.onclick = function() {if (isSending) {xhr.abort();}xhr = new XMLHttpRequest();isSending = true;xhr.open('GET', 'http://localhost:8000/timeout');xhr.send();xhr.onreadystatechange = function() {if (xhr.readyState == 4) {isSending = false;  // 请求发送完成if (xhr.status >= 200 && xhr.status < 300) {console.log(xhr.response);}}};};btn1.onclick = function () {xhr.abort();}
</script>

jQuery 发送 AJAX 请求

get/post 方法

服务端:

app.all('/jquery-server', (request, response) => {response.setHeader('Access-Control-Allow-Origin', '*');const data = {name: "daniel"}response.send(JSON.stringify(data));
});

前端:

<body><div class="container"><h2 class="page-header">jQuery 发送 AJAX 请求</h2><button class="btn btn-primary">GET</button><button class="btn btn-danger">POST</button><button class="btn btn-info">通用型方法 ajax</button></div>
</body>
<script>$('button').eq(0).click(function() {$.get('http://localhost:8000/jquery-server', {a: 100, b: 200}, function(data) {console.log(data);}, 'json');     // 响应体是一个 json 格式数据,而非普通字符串});$('button').eq(1).click(function() {$.post('http://localhost:8000/jquery-server', {a: 100, b: 200}, function(data) {console.log(data);});});
</script>

通用方法

通用方法可以设置任意 http 请求字段

<script>$('button').eq(2).click(function() {$.ajax({url: 'http://localhost:8000/timeout',data: {a: 100, b: 200},type: 'GET',dataType: 'json',       // 响应体结果success: function(data) {console.log(data);},timeout: 2000,error: function(data) {console.log("error!!!")},headers: {a: 300,b: 400}});});
</script>

axios 发送 AJAX 请求

服务端:

const express = require('express');
const app = express();app.all('/server', (request, response) => {// 允许跨域response.setHeader('Access-Control-Allow-Origin', '*');response.setHeader('Access-Control-Allow-Headers', '*');response.send('hello, world');
});app.listen(8000, () => {console.log("listening on 8000");
})app.all('/axios-server', (request, response) => {// 允许跨域response.setHeader('Access-Control-Allow-Origin', '*');response.setHeader('Access-Control-Allow-Headers', '*');const data = {name: 'daniel'};response.send(JSON.stringify(data));
});

前端:

<body><button>GET</button><button>POST</button><button>AJAX</button>
</body>
<script>const btns = document.querySelectorAll('button');axios.defaults.baseURL = 'http://localhost:8000';btns[0].onclick = function() {axios.get('/axios-server', {params: {id: 100,vip: 7},headers: {name: 'daniel',age: 18}}).then(value => {console.log(value);});}btns[1].onclick = function() {axios.post('axios-server', {username: 'admin',password: '123456'}, {params: {id: 200,vip: 8},headers: {height: 180,weight: 80}});}
</script>

axios 函数发送 ajax 请求

函数语法:

// Send a POST request
axios({method: 'post',url: '/user/12345',data: {firstName: 'Fred',lastName: 'Flintstone'}
});

前端代码:

    btns[2].onclick = function() {axios({method: 'POST',url: '/axios-server',params: {vip: 10,level: 30},headers: {a: 100,b: 200},data: {username: 'admin',password: '123456'}}).then(response => {console.log(response.status);console.log(response.statusText);console.log(response.headers);console.log(response.data);});}

fetch 函数发送 AJAX 请求

服务端:

app.all('/fetch-server', (request, response) => {// 允许跨域response.setHeader('Access-Control-Allow-Origin', '*');response.setHeader('Access-Control-Allow-Headers', '*');const data = {name: 'daniel'};response.send(JSON.stringify(data));
});

前端:

<body><button>ajax</button>
</body>
<script>const btn = document.querySelector('button');btn.onclick = function() {fetch('http://localhost:8000/fetch-server', {method: 'POST',headers: {name: 'daniel'},body: 'username=admin&password=admin'}).then(response => {// return response.text();return response.json();}).then(response => {console.log(response);});}
</script>

同源策略

同源策略是一种安全策略,所谓“同源”就是指协议,域名,端口号完全相同。违背同源策略的行为就是跨域

AJAX 默认是需要遵守同源策略的

多台服务器就存在跨域问题

服务端:

const express = require('express');
const app = express();app.all('/home', (request, response) => {response.sendFile(__dirname + '/home.html');
});app.all('/data', (request, response) => {response.send('userdata');
});app.listen(9000, () => {console.log("listening 9000");
});

前端:

<body><h1>daniel</h1><button onclick="">get userdata</button>
</body>
<script>const btn = document.querySelector('button');btn.onclick = function() {const x = new XMLHttpRequest();// 满足同源策略,url 可以简写x.open('GET', '/data');x.send();x.onreadystatechange = function() {if (x.readyState === 4) {if (x.status >= 200 && x.status < 300) {console.log(x.response);}}}}
</script>

JSONP

JSONP 原理

JSON with padding

JSONP 是一个非官方的跨域解决方案,只支持 get 请求

JSONP 利用网页中有一些标签天生具有跨域能力,比如 img link iframe script 等

在前端声明 handle 函数,在 script 中引用:

const data = {name: 'daniel'
};handle(data)
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>jsonp</title><style>#result{width: 300px;height: 100px;border: solid 5px #78a;}</style>
</head>
<body><div id="result"></div><script>function handle(data) {const result = document.getElementById('result');result.innerHTML = data.name;}</script>
</body>
<script src="jsonp.js"></script>
</html>

script 中请求到的 js 代码会立即被解释执行

使用 script 标签完成跨域请求:

<script src="http://localhost:8000/jsonp-server"></script>

服务端对应如下规则:

app.all('/jsonp-server', (request, response) => {response.send('hello, jsonp-server');
});

响应能够正常返回,但是 console 爆 jsonp-server:1 Uncaught ReferenceError: hello is not defined 错误,原因在于相应内容被当作 js 代码解释执行了

app.all('/jsonp-server', (request, response) => {response.send('console.log("hello, jsonp-server")');
});

jsonp:返回一个函数调用语句,其实参就是需要返回的数据,函数的定义在前端,函数的实参在后端传入。服务端代码如下:

app.all('/jsonp-server', (request, response) => {const data = {name: 'daniel'};let data_str = JSON.stringify(data);response.end(`handle(${data_str})`);
});

JSONP 实践

步骤:

  • 创建 script 标签
  • 设置 src 为跨域目标地址,向服务端请求“js代码”
  • 将 script 添加到 body

前端定义 handle 函数,后端返回一个函数调用的 js 代码,其中的实参由对象的字面量得到

服务端代码:

app.all('/check-username', (request, response) => {const data = {exist: 1,msg: 'username exists'};let data_str = JSON.stringify(data);response.end(`handle(${data_str})`);
});

前端代码:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>user</title>
</head>
<body>用户名:<input type="text" id="username"><p></p>
</body>
<script>const input = document.querySelector('input');const p = document.querySelector('p');function handle(data) {input.style.border= 'solid 2px #f00'p.innerHTML = data.msg;}input.onblur = function() {let uname = this.value;const script = document.createElement('script');script.src = 'http://localhost:8000/check-username';document.body.appendChild(script);}
</script>
</html>

jquery 发送 JSONP 请求

前端:

<body><button>jsonp request</button><div id="result"></div>
</body>
<script>$('button').eq(0).click(function(){$.getJSON('http://localhost:8000/jquery-jsonp-server?callback=?', function(data) {$('#result').html(`姓名:${data.name},校区:${data.city}`);});});
</script>

服务端:

app.all('/jquery-jsonp-server', (request, response) => {const data = {name: 'daniel',city: ['bj', 'sh', 'sz']};let data_str = JSON.stringify(data);let cb = request.query.callback;response.end(`${cb}(${data_str})`);
});

CORS

Cross Origin Resource Sharing,跨域资源共享。CORS 是官方的跨域解决方案,它不需要在客户端做任何特殊操作,完全在服务器中进行处理,支持 get 和 post 请求。CORS 标准新增了一组 HTTP 首部字段,允许服务器声明哪些源站通过浏览器有权访问哪些资源

服务端:

app.all('/cors-server', (request, response) => {// 允许跨域response.setHeader('Access-Control-Allow-Origin', '*');response.send('hello, cors');
});

前端:

<body><button>cors request</button><div id="result"></div>
</body>
<script>const btn = document.querySelector('button');btn.onclick = function() {const x = new XMLHttpRequest();x.open('GET', 'http://localhost:8000/cors-server');x.send();x.onreadystatechange = function() {if (x.readyState === 4) {if (x.status >= 200 && x.status < 300) {console.log(x.response);}}};}
</script>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/136920.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C++初阶(九)内存管理

&#x1f4d8;北尘_&#xff1a;个人主页 &#x1f30e;个人专栏:《Linux操作系统》《经典算法试题 》《C》 《数据结构与算法》 ☀️走在路上&#xff0c;不忘来时的初心 文章目录 一、C/C内存分布1、选择题2、填空题3、sizeof 和 strlen 区别&#xff1f;4、总结 二、 C语言…

适用于 iOS 的 10 个最佳数据恢复工具分享

在当今的数字时代&#xff0c;我们的移动设备占据了我们生活的很大一部分。从令人难忘的照片和视频到重要的文档和消息&#xff0c;我们的 iOS 设备存储了大量我们无法承受丢失的数据。然而&#xff0c;事故时有发生&#xff0c;无论是由于软件故障、无意删除&#xff0c;甚至是…

rabbitMq虚拟主机概念

虚拟主机是RabbitMQ中的一种逻辑隔离机制&#xff0c;用于将消息队列、交换机以及其他相关资源进行隔离。 在RabbitMQ中&#xff0c;交换机&#xff08;Exchange&#xff09;用于接收生产者发送的消息&#xff0c;并根据特定的路由规则将消息分发到相应的队列中。而虚拟主机则…

Unity地面交互效果——5、角色足迹的制作

大家好&#xff0c;我是阿赵。   之前几篇文章&#xff0c;已经介绍了地面交互的轨迹做法。包括了法线、曲面细分还有顶点偏移。Shader方面的内容已经说完了&#xff0c;不过之前都是用一个球来模拟轨迹&#xff0c;这次来介绍一下&#xff0c;怎样和角色动作结合&#xff0c…

大语言模型(LLM)综述(七):大语言模型设计应用与未来方向

A Survey of Large Language Models 前言8 A PRACTICAL GUIDEBOOK OF PROMPT DESIGN8.1 提示创建8.2 结果与分析 9 APPLICATIONS10 CONCLUSION AND FUTURE DIRECTIONS 前言 随着人工智能和机器学习领域的迅速发展&#xff0c;语言模型已经从简单的词袋模型&#xff08;Bag-of-…

洛谷 Equalize the Remainders

洛谷没提供中文题面&#xff0c;这里大致翻译一下&#xff1a; 可以进行的操作&#xff1a;任选一个数加一。 一共有n个整数&#xff0c;还有一个约数m&#xff0c;n个数都对m进行求余&#xff0c;累计余数的数量&#xff0c;要求每个余数都有n/m个。 对于样例1的输入&#xff…

【微软技术栈】C#.NET 正则表达式源生成器

本文内容 已编译的正则表达式源生成在源生成的文件中何时使用 正则表达式 (regex) 是一个字符串&#xff0c;它使开发人员能够表达要搜索的模式&#xff0c;使其成为搜索文本和提取结果作为已搜索字符串子集的一种很常见的方法。 在 .NET 中&#xff0c;System.Text.RegularE…

支持C#的开源免费、新手友好的数据结构与算法入门教程 - Hello算法

前言 前段时间完成了C#经典十大排序算法&#xff08;完结&#xff09;然后有很多小伙伴问想要系统化的学习数据结构和算法&#xff0c;不知道该怎么入门&#xff0c;有无好的教程推荐的。今天给大家推荐一个支持C#的开源免费、新手友好的数据结构与算法入门教程&#xff1a;He…

C# wpf 实现任意控件(包括窗口)更多拖动功能

系列文章目录 第一章 Grid内控件拖动 第二章 Canvas内控件拖动 第三章 任意控件拖动 第四章 窗口拖动 第五章 附加属性实现任意拖动 第六章 拓展更多拖动功能&#xff08;本章&#xff09; 文章目录 系列文章目录前言一、添加的功能1、任意控件MoveTo2、任意控件DragMove3、边…

【STM32】STM32的Cube和HAL生态

1.单片机软件开发的时代变化 1.单片机的演进过程 (1)第1代&#xff1a;4004、8008、Zilog那个年代&#xff08;大约1980年代之前&#xff09; (2)第2代&#xff1a;51、PIC8/16、AVR那个年代&#xff08;大约2005年前&#xff09; (3)第3代&#xff1a;51、PIC32、Cortex-M0、…

解决IDEA使用卡顿的问题

*问题&#xff1a;使用IDEA的时候卡顿 原因&#xff1a;IDEA默认分配的内存有上限 **可以查看内存分配情况及使用情况__ 解决&#xff1a; 设置JVM的启动参数&#xff1a; 进入idea的安装目录的bin文件夹 -Xms1024m -Xmx2048m -XX:ReservedCodeCacheSize1024m -XX:UseG1G…

IP-guard WebServer RCE漏洞复现

0x01 产品简介 IP-guard是由溢信科技股份有限公司开发的一款终端安全管理软件&#xff0c;旨在帮助企业保护终端设备安全、数据安全、管理网络使用和简化IT系统管理。 0x02 漏洞概述 漏洞成因 在Web应用程序的实现中&#xff0c;参数的处理和验证是确保应用安全的关键环节…

springboot中定时任务cron不生效,fixedRate指定间隔失效,只执行一次的问题

在调试计算任务的时候&#xff0c;手动重置任务为初始状态&#xff0c;但是并没有重新开始计算&#xff0c;检查定时任务代码&#xff1a; 从Scheduled(fixedRate 120000)可以看到&#xff0c;应该是间隔120秒执行一次该定时任务&#xff0c;查看后台日志&#xff0c;并没有重…

Uniapp实现多语言切换

前言 之前做项目过程中&#xff0c;也做过一次多语言切换&#xff0c;大致思想都是一样的&#xff0c;想了解的可以看下之前的文章C#WinForm实现多语言切换 使用i18n插件 安装插件 npm install vue-i18n --saveMain.js配置 // 引入 多语言包 import VueI18n from vue-i18n…

OpenGL_Learn08(坐标系统与3D空间)

目录 1. 概述 2. 局部空间 3. 世界空间 4. 观察空间 5. 剪裁空间 6. 初入3D 7. 3D旋转 8. 多个正方体 9. 观察视角 1. 概述 OpenGL希望在每次顶点着色器运行后&#xff0c;我们可见的所有顶点都为标准化设备坐标(Normalized Device Coordinate, NDC)。也就是说&#x…

关于 国产系统UOS系统Qt开发Tcp服务器外部连接无法连接上USO系统 的解决方法

若该文为原创文章&#xff0c;转载请注明原文出处 本文章博客地址&#xff1a;https://hpzwl.blog.csdn.net/article/details/134254817 红胖子(红模仿)的博文大全&#xff1a;开发技术集合&#xff08;包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软…

Termius for Mac:掌控您的云端世界,安全高效的SSH客户端

你是否曾经在Mac上苦苦寻找一个好用的SSH客户端&#xff0c;让你能够远程连接到Linux服务器&#xff0c;轻松管理你的云端世界&#xff1f;现在&#xff0c;我们向你介绍一款强大而高效的SSH客户端——Termius。 Termius是一款专为Mac用户设计的SSH客户端&#xff0c;它提供了…

this.$message提示内容添加换行

0 效果 1 代码 let msgArr [只允许上传doc/docx/xls/xlsx/pdf/png/jpg/bmp/ppt/pptx/rar/zip格式文件,且单个文件大小不能超过20MB,已过滤无效的文件] let msg msgArr.join(<br/>) this.$message({dangerouslyUseHTMLString: true,message: msg,type: warning })

安卓 车轮视图 WheelView kotlin

安卓 车轮视图 WheelView kotlin 前言一、代码解析1.初始化2.初始化数据3.onMeasure4.onDraw5.onTouchEvent6.其他 6.ItemObject二、完整代码总结 前言 有个需求涉及到类似这个视图&#xff0c;于是在网上找了个轮子&#xff0c;自己改吧改吧用&#xff0c;拿来主义当然后&…

物联网中的毫米波雷达:连接未来的智能设备

随着物联网&#xff08;IoT&#xff09;技术的飞速发展&#xff0c;连接设备的方式和效能变得越来越重要。毫米波雷达技术作为一种先进的感知技术&#xff0c;正在为物联网设备的连接和智能化提供全新的可能性。本文将深入探讨毫米波雷达在物联网中的应用&#xff0c;以及它是如…