什么是Ajax
Ajax
的全称是 Asynchronous JavaScript and XML(异步的 JavaScript 和 XML),是一种用于创建动态网页(与后端交互)的技术。
Ajax 技术
指的是脚本独立向服务器请求数据,拿到数据以后,进行处理并更新网页。整个过程中,后端只是负责提供数据,其他事情都由前端处理,实现了 获取数据 → 处理数据 → 展示数据
的完整业务逻辑。
同步与异步
同步
所有的操作都做完,才返回给用户。这样用户在线等待的时间太长,给用户一种卡死了的感觉(就是系统迁移中,点击了迁移,界面就不动了,但是程序还在执行,卡死了的感觉)。这种情况下,用户不能关闭界面,如果关闭了,即迁移程序就中断了。
异步
将用户请求放入消息队列,并反馈给用户,系统迁移程序已经启动,你可以关闭浏览器了。然后程序再慢慢地去写入数据库去。这就是异步。但是用户没有卡死的感觉,会告诉你,你的请求系统已经响应了。你可以关闭界面了。
工作原理
在客户端(如浏览器)和服务器之间加了一个中间层:Ajax 引擎
。由 Ajax 引擎独立向服务器请求数据,前端获取到 Ajax 返回的数据后,可以使用新数据来更新页面、或进行其它操作,使用户请求和服务器响应异步化,从而保证了在不刷新页面的前提下可以局部更新
网页内容。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Ajax</title>
</head>
<body>
<div id="view">
<p>点击下面的按钮,将 Ajax 请求回来的数据更新在该文本内</p>
</div>
<button type="button" id="btn">发起 Ajax 请求</button>
<script>
document.getElementById("btn").onclick = ajaxRequest;
function ajaxRequest () {
//实例化一个XMLHttpRequest对象
var xhr = new XMLHttpRequest();
//open()规定请求的类型、url、是否异步
xhr.open("GET","https://www.w3cschool.cn/statics/demosource/ajax_info.txt", true);
xhr.send();
//send()发送请求,必须结合open一起使用
xhr.onreadystatechange = function(){
//监测服务器响应的状态
if (xhr.readyState === 4 && xhr.status === 200) {
//当 readyState 等于 4 且状态为 200 时,表示成功响应
document.getElementById("view").innerHTML = xhr.responseText;
}
}
}
</script>
</body>
优点与缺点
优点:
- 页面无刷新更新,用户的体验非常好;
- 异步通信,响应更快
- 可以将一些服务器工作转移到客户端,利用客户端资源来处理,减轻服务器和带宽的压力,节约空间和带宽租用成本;
- 技术标准化,并被
浏览器广泛支持
,不需要下载插件或者小程序; - Ajax 可使因特网应用程序更小、更快、更友好。
缺点:
- Ajax 不支持浏览器 back 返回按钮;
- 有安全问题,Ajax 暴露了与服务器交互的细节;
- 对搜索引擎不友好;
- 破坏了程序的异常机制;
- 不容易调试。
同源策略
url的组成
一个 URL 地址可以有以下几个组成部分:scheme
: //host
:post
/path
?query
#fragment
- scheme:通信协议,一般为 http 、https;
- host:域名;
- post:端口号,此项为可选项,http 协议默认的端口号为 80,https 协议默认的端口号为 443;
- path:路径,由 "/ "隔开的字符串;
- query:查询参数,此项为可选项;
- fragment:信息片段,用于指定网络资源中的某片断,此项为可选项;
网址:https://www.w3cschool.cn:8080/search?w=ajax
https
是协议;www.w3cschool.cn
是域名;8080
是端口号;/search
是路径;?w=ajax
是 URL 地址带的参数;- 缺少
fragment
信息片段;
什么是同源策略
同源策略
是一种安全协议,是客户端脚本(尤其是 JavaScript)中重要的安全度量标准,指一段脚本只能读取同一来源的窗口和文档的属性。
何为同源?
同源指的是 URL 地址中的 协议、域名、端口 三者 都 相同。
路径不同,同源
- www.w3cschool.cn
- www.w3cschool.cn/tutorial
- www.w3cschool.cn/minicourse/…
协议不同,不同源
- www.w3cschool.cn
- www.w3cschool.cn
域名不同,不同源
- pm.w3cschool.cn
- www.w3cschool.cn
端口不同,不同源
- www.pm.w3cschool.cn
- www.pm.w3cschool.cn:445
为什么要有同源策略
我们在使用 Ajax 请求后端数据时,只能跟同源的后端接口进行数据交互
,即:后端接口的 URL 与发起 Ajax 请求的页面 URL 之间,需要满足同源策略。
不满足 "同源策略" 的请求浏览器通常都会报错,下面是一个 本地服务器 请求 远程服务器 产生的报错信息:
为了数据的安全性
。若没有同源策略的限制,那么黑客就可以在他的页面上任意请求你的后端数据,造成数据库内容被盗取、隐私数据泄漏。
跨域请求
虽然 Ajax 请求需要满足同源策略,然而在一些场景中,你真的需要 Ajax 访问其它 "源" 的数据(称为跨域访问),这时需要后端服务器进行相应的设置。
如果服务器端支持 CORS,可以通过设置Access-Control-Allow-Origin
来实现跨域。如果浏览器检测到相应的设置,就会允许 Ajax 进行跨域访问。
解决跨域的方式:
- JSONP 技术
- 在服务端设置代理模块;
- 通过修改 window.name 实现跨域;
- 使用 HTML5 中新引进的 window.postMessage 方法来跨域传送数据;
- 等...
XMLHttpRequest
Ajax 技术的核心
是XMLHttpRequest
类,简称 XHR,它允许脚本异步调用
HTTP API。浏览器在XMLHttpRequest
类上定义了 HTTP API,这个类的每个实例都表示一个 独立 的 请求/响应 对象,并且这个实例对象上的属性和方法允许 指定细节 和 提取响应数据。
创建实例
var xhr = new XMLHttpRequest();
兼容
绝大多数的浏览器都支持XMLHttpRequest
。但
在 IE7 之前的版本(IE5、IE6)并不支持XMLHttpRequest()
构造函数,它们需要使用ActiveX
对象进行模拟:
var xhr = new ActiveXObject("Microsoft.XMLHTTP");
兼容写法
var xhr = window.XMLHttpRequest ? new window.XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP");
open()
创建 XMLHttpRequest 对象之后,发起 HTTP 请求的下一步
是调用 XMLHttpRequest 对象的open
方法,指定 HTTP 请求的两个必需部分:请求方法 和 URL
xhr.open(method, url, async)
-
method:
-
第一个参数用于指定 HTTP 请求的方法,不区分大小写;
-
该参数可取的值包括:"GET"、"POST"、"HEAD"、"PUT"、"OPTIONS"、"DELETE",其中,"GET" 和 "POST" 是得到广泛支持的请求方法;
-
-
url:
-
第二个参数用于指定 HTTP 请求的 URL 地址,可以是 绝对URL 或 相对URL;
-
绝对URL:需要满足 "同源策略"(服务器明确允许跨域请求的情况除外);
-
相对URL:即相对于文档的 URL;
-
-
async:
-
第三个参数是可选的,可用
布尔值
指定脚本是否以异步的方式调用此次 Ajax 请求; -
该参数默认为 true,表示异步调用此次 Ajax 请求,不阻塞后续脚本的执行;
-
注意:
open()
方法其实还可以有第四、第五个参数,分别是用于 HTTP 请求访问认证的用户名和密码
,使用它们需要在服务器做相应的配置,较为少用。
setRequestHeader
如果你的 HTTP 请求需要设置请求头
,那么调用 open 方法之后的下个步骤
就是设置它,使用的方法是:setRequestHeader
// 在 open 方法之后设置请求头
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xhr.setRequestHeader(name, value)
- name:请求头名称;
- value:请求头的值。
send()
使用 XMLHttpRequest 发起 HTTP 请求
的最后一步
是指定可选的请求主体、并向服务器发送它,使用的方法是:send
var xhr = new XMLHttpRequest();
xhr.open("GET", "/statics/demosource/demo_get_json.php");
// 由于GET请求,没有请求主体,所以在调用 send 方法时可以传递 null或省略这个参数;
xhr.send(null);
var xhr = new XMLHttpRequest();
xhr.open("POST", "/statics/demosource/demo_post_json.php");
// 把 msg 作为请求主体发送
xhr.send(msg);
- POST 请求通常都拥有请求主体,可在 send 方法中指定它;
- POST 请求的请求主体,
应该匹配
setRequestHeader
方法所指定的 "Content-Type" 头。
获取响应
一个完整的 HTTP 响应由 状态码、响应头和 响应主体
组成,这三者都可以通过XMLHttpRequest
对象提供的属性和方法获取。
如何确定 HTTP 请求已经返回了响应内容呢?
为了能够在 HTTP 响应准备就绪时得到通知,必须监听XMLHttpRequest
对象上的readystatechange
事件。但为了理解这个事件类型,需要先了解下readyState
属性,因为该事件监听的是readyState
属性值的改变。
XMLHttpRequest
对象上的readyState
属性在 HTTP 请求过程中,会从 0 变到 4
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Tryrun 2</title>
</head>
<body>
<button id="btn">点我观察 readyState 属性的改变</button>
<script>
var oBtn = document.getElementById("btn");
oBtn.onclick = function () {
//兼容处理
var xhr = window.XMLHttpRequest ? new window.XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP");
alert(xhr.readyState);//0
xhr.onreadystatechange = function () {
alert(xhr.readyState);
}
xhr.open("GET", "/statics/demosource/demo_get_json.php");
xhr.send();
}
</script>
</body>
</html>
readyState 属性
readyState
属性是一个整数,它的值代表了不同的 HTTP 请求状态。
- 0:初始值,表示请求未初始化,
open
方法尚未调用; - 1:启动请求,open 方法已经调用,但尚未调用 send 方法;
- 2:请求发送,已经调用 send 方法,但尚未接收到响应;
- 3:接收响应,已经接受到
部分响应
数据,主要是响应头; - 4:HTTP 响应完成,已经接收到全部响应数据,而且可以在客户端使用。
每次readyState
属性值的改变都会触发readystatechange
事件,但只有readyState
属性值为 4 时才是我们所关心的状态,因为只有这个状态才表示 HTTP 的响应准备就绪,可以真正意义上的结合服务器所响应的数据来实现我们的业务需求。
发送请求规范
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Tryrun 3</title>
</head>
<body>
<button id="btn">点我观察 readyState 属性的改变</button>
<div id="tip"></div>
<script>
var oBtn = document.getElementById("btn"),
oTip = document.getElementById("tip");
oBtn.onclick = function () {
var xhr = window.XMLHttpRequest ? new window.XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP");
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
oTip.innerText = "HTTP 响应完成";
}
};
xhr.open("GET", "/statics/demosource/demo_get_json.php");
xhr.send();
}
</script>
</body>
</html>
注意:
readyState
的属性值只代表此时的 HTTP 请求处于哪个阶段:是发送了请求还是未发送请求,是只接收到了响应头还是响应完成;- "响应完成" 只代表 HTTP 请求结束,至于服务器的响应状态:是请求成功还是请求错误,又或者是服务器错误,需要通过
HTTP 状态码
判断,它存储在XMLhttpRequest
的status
属性上;
status属性
status
属性会以数字的形式保存服务器响应的 HTTP 状态码,诸如使用最频繁的 "200" 表示请求成功,"404" 表示 URL 不能匹配服务器上的任何资源。
HTTP 状态码
是用来表示网页服务器响应状态的 3 位
数字代码,所有状态码的第一个数字代表了响应的五种状态之一:
- 1xx:临时响应
- 2xx:成功
- 3xx:重定向
- 4xx:请求错误
- 5xx:服务器错误
哪些 HTTP 状态码表示我们可以获取到 HTTP 响应数据呢?
2开头的状态码 与 304。2开头的状态码都表示请求成功,而 304 是对客户端可读取缓存的一种响应,同样能获取到 HTTP 的响应数据。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Tryrun 4</title>
<style>
#btn { margin-top: 7px; }
</style>
</head>
<body>
<div id="tip"></div>
<button id="btn">点我发起 Ajax 请求</button>
<script>
var oBtn = document.getElementById("btn"),
oTip = document.getElementById("tip");
oBtn.onclick = function () {
var xhr = window.XMLHttpRequest ? new window.XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP");
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) return;
if (xhr.status >= 200 && xhr.status < 300 || xhr.status === 304) {
oTip.innerText = "HTTP 请求成功";
}
};
xhr.open("GET", "/statics/demosource/demo_get_json.php");
xhr.send();
}
</script>
</body>
</html>
responseText 属性
responseText
属性以字符串的形式存储了响应主体,即:服务器的响应数据。
无论返回的数据类型是什么,响应主体的内容都会保存在responseText
属性中;
响应html
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
if (xhr.readyState !== 4) return;
if (xhr.status >= 200 && xhr.status < 300 || xhr.status === 304) {
// 当响应成功,获取响应数据,将数据赋值给本地
oView.innerHTML = xhr.responseText;
}
};
xhr.open("GET", "/statics/demosource/demo_get.php");
xhr.send();
响应json
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
if (xhr.readyState !== 4) return;
if (xhr.status >= 200 && xhr.status < 300 || xhr.status === 304) {
// 使用JSON.parse把 响应数据转换为json数据
var res = JSON.parse(xhr.responseText);
// 将响应数据中的data属性赋值给oTime做内容
oTime.innerText = res.data;
}
};
xhr.open("GET", "/statics/demosource/demo_get_json.php");
xhr.send();
查询 HTTP 响应头的方法
在XMLHttpRequest
对象上,可通过getAllResponseHeaders
和getResponseHeader
方法查询响应头信息。
getAllResponseHeaders
getAllResponseHeaders
方法无参数,用于一次性返回可查询的全部响应头信息
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
if (xhr.readyState !== 4) return;
if (xhr.status >= 200 && xhr.status < 300 || xhr.status === 304) {
// 获取所有可查询的响应头信息
oView.innerText = xhr.getAllResponseHeaders();
}
};
xhr.open("GET", "/statics/demosource/demo_get_json.php");
xhr.send();
getResponseHeader
getResponseHeader
方法用于查询单一
响应头信息,需要传入一个指定 "头名称" 的字符串作为参数:getResponseHeader(headerName)
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
if (xhr.readyState !== 4) return;
if (xhr.status >= 200 && xhr.status < 300 || xhr.status === 304) {
// 查询 "Content-Type" 响应头信息
alert( xhr.getResponseHeader("Content-Type") );
}
};
xhr.open("GET", "/statics/demosource/demo_get_json.php");
xhr.send();
注意:
由于XMLHttpRequest
会自动处理 cookie,将 cookie 从getAllResponseHeaders
方法返回的响应头集合中过滤掉,并且如果给getResponseHeader
方法传递 "Set-Cookie" 或 "Set-Cookie2",则返回 null。
同步响应
var xhr = new XMLHttpRequest();
// 指定 open 方法的第三个参数为 false
xhr.open("GET", "/statics/demosource/demo_get_json.php", false);
// send 方法的调用将阻塞后面代码的执行,直到此次 HTTP 请求完成
xhr.send();
// 不再需要监听 readystatechange 事件
if (xhr.status >= 200 && xhr.status < 300 || xhr.status === 304) {
oTime.innerText = JSON.parse(xhr.response).date;
} else {
// 如果请求不成功,就报错
throw new Error(xhr.status);
}
abort 中止请求
若 HTTP 请求的时间超出预期,可以调用XMLHttpRequest
对象上的abort
方法来中止 HTTP 请求。
var xhr = new XMLHttpRequest();
var timer = null; // 用于存储定时器标识
xhr.onreadystatechange = function () {
if (xhr.readyState !== 4) return;
if (xhr.status >= 200 && xhr.status < 300 || xhr.status === 304) {
clearTimeout(timer); // 未超时则取消定时器
}
};
xhr.open("GET", "/statics/demosource/demo_get_json.php");
xhr.send();
// 2秒后中止此次 GET 请求
timer = setTimeout(function(){
xhr.abort();
}, 2000)
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!