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.rhkb.cn/news/186245.html

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

相关文章

C/C++特殊求和 2021年6月电子学会青少年软件编程(C/C++)等级考试一级真题答案解析

目录 C/C幻数求和 一、题目要求 1、编程实现 2、输入输出 二、算法分析 三、程序编写 四、程序说明 五、运行结果 六、考点分析 C/C幻数求和 2021年6月 C/C编程等级考试一级编程题 一、题目要求 1、编程实现 如果一个数能够被7整除或者十进制表示中含有数字7&…

P02项目诊断报警组件(学习操作日志记录、单元测试开发)

★ P02项目诊断报警组件 诊断报警组件的主要功能有&#xff1a; 接收、记录硬件设备上报的报警信息。从预先设定的错误码对照表中找到对应的声光报警和蜂鸣器报警策略&#xff0c;结合当前的报警情况对设备下发报警指示。将报警消息发送到消息队列&#xff0c;由其它组件发送…

高级运维学习(十五)Zabbix监控(二)

一 Zabbix 报警机制 1 基本概念 自定义的监控项默认不会自动报警首页也不会提示错误需要配置触发器与报警动作才可以自动报警 2 概念介绍 &#xff08;1&#xff09;触发器 (trigger) 表达式&#xff0c;如内存不足300M&#xff0c;用户超过30个等 当触发条件发生后&a…

mac 卸载第三方输入法

输入法设置里的移除&#xff0c;并不是真的卸载&#xff0c;点击还是能添加回来 在活动监视器里强制退出此输入法在访达界面使用快捷键 ShiftcommandG在弹出的对话框内输入以下路径&#xff08;/资源库/Input Methods&#xff09;&#xff0c;再点击下面的前往找到你要卸载的输…

【第2章 Node.js基础】2.3 Node.js事件机制

2.3 Node.js事件机制 学习目标 &#xff08;1&#xff09;理解Node.js的事件机制&#xff1b; &#xff08;2&#xff09;掌握事件的监听与触发的用法。 文章目录 2.3 Node.js事件机制什么是事件机制为什么要有事件机制事件循环事件的监听与触发EventEmitter类常用API 什么是…

LabVIEW如何才能得到共享变量的引用

LabVIEW如何才能得到共享变量的引用 有一个LabVIEW 库文件 (.lvlib) &#xff0c;其中有一些定义好的共享变量。但需要得到每个共享变量的引用以便在程序运行时访问其属性。 共享变量的属性定义在“变量”类属性节点中。为了访问变量类&#xff0c;共享变量的引用必须连接到变…

Leetcode Hot 100之四:283. 移动零+11. 盛最多水的容器

283.移动零 题目&#xff1a; 给定一个数组 nums&#xff0c;编写一个函数将所有 0 移动到数组的末尾&#xff0c;同时保持非零元素的相对顺序。 请注意 &#xff0c;必须在不复制数组的情况下原地对数组进行操作。 示例 1: 输入: nums [0,1,0,3,12] 输出: [1,3,12,0,0] …

数据结构与算法—双链表

前言 前面有很详细的讲过线性表(顺序表和链表)&#xff0c;当时讲的链表以单链表为主&#xff0c;但在实际应用中双链表有很多应用场景&#xff0c;例如大家熟知的LinkedList。 双链表与单链表区别 单链表和双链表都是线性表的链式实现&#xff0c;它们的主要区别在于节点结构…

048-第三代软件开发-数据回放

第三代软件开发-数据回放 文章目录 第三代软件开发-数据回放项目介绍数据回放 关键字&#xff1a; Qt、 Qml、 Data、 play back、 数据 项目介绍 欢迎来到我们的 QML & C 项目&#xff01;这个项目结合了 QML&#xff08;Qt Meta-Object Language&#xff09;和 C 的…

【C++】单例模式【两种实现方式】

目录 一、了解单例模式前的基础题 1、设计一个类&#xff0c;不能被拷贝 2、设计一个类&#xff0c;只能在堆上创建对象 3、设计一个类&#xff0c;只能在栈上创建对象 4、设计一个类&#xff0c;不能被继承 二、单例模式 1、单例模式的概念 2、单例模式的两种实现方式 …

Qt工程打包工具 windeployqt 的用法

1.复制工程下的“Debug”或者“Release”文件夹到你喜欢的路径&#xff0c;例如&#xff1a;D:\QT_out\ 2.在操作系统“开始”选项找到“Qt”文件夹&#xff0c;打开“Qt 5.15.2&#xff08;MSVC 2019 64-bit&#xff09;” 重点&#xff1a; 这里要注意的是&#xff0c;一定…

Linux常见指令:从基础到理论

前言 目录 前言 1. find指令 拓展 2. grep指令 拓展 sort指令 uniq指令 wc指令 3. zip/unzip指令 4. tar指令 5. uname指令 拓展 6. Linux常用热键 7. 关机 8. rz指令 拓展 scp指令 9. shell命令以及运行原理 Linux常见指令是使用Linux系统时必不可少的一部分。通过掌握…

简单好看个人引导页毛玻璃页面 HTML 源码

毛玻璃个人引导页源码&#xff0c;界面简洁&#xff0c;已测可完美搭建&#xff0c;UI非常不错的&#xff0c;有兴趣的自行去安装体验吧&#xff0c;其它就没什么好介绍的了。 学习资料源代码&#xff1a;百度网盘 请输入提取码&#xff1a;ig8c

[RCTF 2019]nextphp

文章目录 考点前置知识PHP RFC&#xff1a;预加载FFI基本用法PHP RFC&#xff1a;新的自定义对象序列化机制 解题过程 考点 PHP伪协议、反序列化、FFI 前置知识 PHP RFC&#xff1a;预加载 官方文档 通过查看该文档&#xff0c;在最下面找到预加载结合FFI的危害 FFI基本用法 …

Selenium关于内容信息的获取读取

在进行自然语言处理、文本分类聚类、推荐系统、舆情分析等研究中,通常需要使用新浪微博的数据作为语料,这篇文章主要介绍如果使用Python和Selenium爬取自定义新浪微博语料。因为网上完整的语料比较少,而使用Selenium方法有点简单、速度也比较慢,但方法可行,同时能够输入验…

yolov5 通过视频进行目标检测

打开yolov5-master文件夹&#xff0c;可以看到一个名为data的文件夹&#xff0c;在data中创建一个新的文件夹&#xff0c;命名为videos。 打开yolov5-master中的detect.py可以看到一行代码&#xff08;大概在245行左右&#xff09;为 parser.add_argument(--source, typestr,…

fastspar微生物相关性推断

fastspar 简介 fastspar是基于Sparcc通过C编写的&#xff0c;速度更快&#xff0c;内存消耗更少。sparcc是基于OTU的原始count数&#xff0c;通过log转换和标准化去除传统相对丰度的天然负相关&#xff08;因为所有OTU之和为1&#xff0c;某些OTU丰度高另外一些自然就少&…

tqdm学习

from tqdm import tqdmepochs 10 epoch_bar tqdm(range(epochs)) count 0 for _ in epoch_bar:count count1print("count {}".format(count))print(_)每次就是一个epoch

【Python】数据分析案例:世界杯数据可视化

文章目录 前期数据准备导入数据 分析&#xff1a;世界杯中各队赢得的比赛数分析&#xff1a;先打或后打的比赛获胜次数分析&#xff1a;世界杯中的抛硬币决策分析&#xff1a;2022年T20世界杯的最高得分者分析&#xff1a;世界杯比赛最佳球员奖分析&#xff1a;最适合先击球或追…

JAVA代码视频转GIF(亲测有效)

1.说明 本次使用的是JAVA代码视频转GIF&#xff0c;maven如下&#xff1a; <dependency><groupId>ws.schild</groupId><artifactId>jave-nativebin-win64</artifactId><version>3.2.0</version></dependency><dependency&…