AJAX
概述
A JAX(Asynchronous JavaScript and XML(异步的 JavaScript 和 XML) ),最早出现在 2005 年的 Google Suggest,是在浏览器端进行网络编 程(发送请求、接收响应)的技术方案,它使我们可以通过 JavaScript 直接获取服务端最新的内容而不必重新加载 页面。让 Web 更能接近桌面应用的用户体验。
A JAX 就是浏览器提供的一套 API,可以通过 JavaScript 调用,从而实现通过代码控制请求与响应。实现网络编程。
开发时注意:涉及到AJAX操作的页面“不能”使用文件协议访问(file://),因为不同源,但JSONP可以。
参考http://www.runoob.com/ajax/ajax-xmlhttprequest-create.html
快速上手
// 1. 创建一个 XMLHttpRequest 类型的对象 —— 相当于打开了一个浏览器
var xhr = new XMLHttpRequest();
// 4. 指定 xhr 状态变化事件处理函数 —— 相当于处理网页呈现后的操作
xhr.onreadystatechange = function () {
// 通过 xhr 的 readyState 判断此次请求的响应是否接收完成
if (this.readyState === 4) {
// 通过 xhr 的 responseText 获取到响应的响应体
console.log(this);
}
// 2. 打开与一个网址之间的连接 —— 相当于在地址栏输入访问地址
xhr.open('GET', './time.php');
// 3. 通过连接发送一次请求 —— 相当于回车或者点击访问发送请求
xhr.send(null);
}
创建 XMLHttpRequest 对象(重点)
所有现代浏览器均支持 XMLHttpRequest 对象(IE5 和 IE6 使用ActiveXObject)。
var xmlhttp;
if (window.XMLHttpRequest) {
// IE7+, Firefox, Chrome, Opera, Safari 浏览器执行代码
xmlhttp=new XMLHttpRequest();
} else {
// IE6, IE5 浏览器执行代码
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
向服务器发送请求(重点)
xmlhttp.open("GET","ajax_info.txt",true);
xmlhttp.send();
方法 | 描述 |
---|---|
open(method,url,async) | 规定请求的类型、URL 以及是否异步处理请求。method:请求的类型;GET 或 POST。 url:文件在服务器上的位置。 async:true(异步,推荐)或 false(同步, 请不要编写 onreadystatechange 函数,把代码放到 send() 语句后面即可)。 |
send(string) | 将请求发送到服务器。 string:仅用于 POST 请求。 |
readyState(理解)
onreadystatechange 事件
onreadystatechange事件含有readyState属性和status属性。
由于 readystatechange 事件是在 xhr 对象状态变化时触发(不单是在得到响应时),也就意味着这个事件会被触发多次。
readyState | 状态描述 | 说明 |
---|---|---|
0 | UNSENT | 代理(XHR)被创建,但尚未调用open() 方法。 |
1 | OPENED | open() 方法已经被调用,建立了连接。 |
2 | HEADERS_RECEIVED | send() 方已经调用,并且已经可以获取状态行和响应头。 |
3 | LOADING | 响应体下载中,responseText 属性可能已经包含部分数据。 |
4 | DONE | 响应体下载完成,可以直接使用responseText 。 |
status | 描述 |
---|---|
200 | “OK” |
404 | 未找到页面 |
响应(遵循HTTP)
本质上 XMLHttpRequest 就是 JavaScript 在 Web 平台中发送 HTTP 请求的手段,所以我们发送出去的请求任然是 HTTP 请求,同样符合 HTTP 约定的格式:
PS:xhr.onload是readyState === 4的执行过程。
// 设置请求报文的请求行
xhr.open('GET', './time.php')
// 设置请求头
xhr.setRequestHeader('Accept', 'text/plain')
// 设置请求体
xhr.send(null)
xhr.onreadystatechange = function () {
if (this.readyState === 4) {
// 获取响应状态码
console.log(this.status)
// 获取响应状态描述
console.log(this.statusText)
// 获取响应头信息
console.log(this.getResponseHeader('Content‐Type')) // 指定响应头
console.log(this.getAllResponseHeaders()) // 全部响应头
// 获取响应体
console.log(this.responseText) // 文本形式
console.log(this.responseXML) // XML 形式,了解即可不用了
}
}
属性 | 描述 |
---|---|
status | 响应状态码 |
statusText | 响应状态描述 |
getResponseHeader() | 获取指定响应头 |
getAllResponseHeader() | 获取全部响应头 |
responseText | 获得字符串形式的响应数据(响应体)。 |
responseXML | 获得 XML 形式的响应数据(响应体)。 |
response | 获取的结果会根据this.responseType的变化而变化。默认与responseText一样。(HTML5新属性) |
responseType | 设置请求代理对象。 |
GET请求(重点)
通常在一次GET请求中,参数传递都是通过URL地址中的
?
参数传递
一般情况下 URL 传递的都是参数性质的数据,而 POST 一般都是业务数据。
var xhr = new XMLHttpRequest();
// GET 请求传递参数通常使用的是问号传参
// 这里可以在请求地址后面加上参数,从而传递数据到服务端
xhr.open('GET', './delete.php?id=1');
// 一般在 GET 请求时无需设置响应体,可以传 null 或者干脆不传
xhr.send(null);
xhr.onreadystatechange = function () {
if (this.readyState === 4) {
console.log(this.responseText);
}
}
POST请求(重点)
POST请求过程中,都是采用请求体承载需要提交的数据。
- setRequestHeader():设置一个请求头。
- send(string):将string发送给服务器。
ps:
- 请求头中的contype-type对应html中设置的entype属性。注意传数据给服务器的数据格式的不同,要设置请求头中对应的Content-type。
- post请求利用send()传递参数。
var xhr = new XMLHttpRequest();
// open 方法的第一个参数的作用就是设置请求的 method
xhr.open('POST', './add.php');
// 设置请求头中的 Content‐Type 为 application/x‐www‐form‐urlencoded
// 标识此次请求的请求体格式为 urlencoded 以便于服务端接收数据
xhr.setRequestHeader('Content‐Type', 'application/x‐www‐form‐urlencoded');
// 需要提交到服务端的数据可以通过 send 方法的参数传递
// 格式:key1=value1&key2=value2
xhr.send('key1=value1&key2=value2');
xhr.onreadystatechange = function () {
if (this.readyState === 4) {
console.log(this.responseText);
}
}
同步与异步(推荐异步)
xhr.open()
方法第三个参数要求传入的是一个 bool 值,其作用就是设置此次请求是否采用异步方式执行,默认 为 true ,如果需要同步执行可以通过传递 false 实现。如果采用同步方式执行,则代码会卡死在 xhr.send() 这一步。
响应数据格式
不管服务端是采用XML还是采用JSON本质上都是将数据返回给客户端
服务端一个设置一个合理的Content-Type(Content-Type: application/xml或application/json等)。
XML
一种数据描述手段,基本现在的项目不用了,客户端解析服务端返回的xml文件类似于DOM那样 。 淘汰的原因:数据冗余太多 。
var xhr = new XMLHttpRequest();
xhr.open('GET','xml.php');
xhr.send();
xhr.onreadystatechange = function () {
if (this.readyState != 4)
return;
console.log(this.responseXML.documentElement.children[0].innerHTML);
console.log(this.responseXML.documentElement.getElementsByTagName('name')[0].innerHTML);
}
JSON
也是一种数据描述手段,类似于 JavaScript 字面量方式 服务端采用 JSON 格式返回数据,客户端按照 JSON 格式解析数据。
处理响应数据渲染
模板引擎:
- artTemplate:https://aui.github.io/art-template/
- juicer:https://www.bootcdn.cn/juicer/
- doT:https://github.com/olado/doT
- handlebars:http://handlebarsjs.com/
模板引擎实际上就是一个 API,模板引擎有很多种,使用方式大同小异,目的为了可以更容易的将数据渲染到 HTML中。
script标签如果type不等于text/javascript的话,内部内容不会作为JavaScript执行。
一般使用模板引擎,把script标签的type设为text/x-模板引擎名。
封装
AJAX请求封装
/**
* 发送一个 AJAX 请求
* @param {String} method 请求方法
* @param {String} url 请求地址
* @param {Object} params 请求参数
* @param {Function} done 请求完成过后需要做的事情(委托/回调)
*/
function ajax (method, url, params, done) {
// 统一转换为大写便于后续判断
method = method.toUpperCase();
// 对象形式的参数转换为 urlencoded 格式
var pairs = [];
for (var key in params) {
pairs.push(key + '=' + params[key]);
}
var querystring = pairs.join('&');
var xhr = window.XMLHttpRequest ? new XMLHttpRequest() : new
ActiveXObject('Microsoft.XMLHTTP');
xhr.addEventListener('readystatechange', function () {
if (this.readyState !== 4) return;
// 尝试通过 JSON 格式解析响应体
try {
done(JSON.parse(this.responseText));
} catch (e) {
done(this.responseText);
}
});
// 如果是 GET 请求就设置 URL 地址 问号参数
if (method === 'GET') {
url += '?' + querystring;
}
xhr.open(method, url);
// 如果是 POST 请求就设置请求体
var data = null;
if (method === 'POST') {
xhr.setRequestHeader('Content‐Type', 'application/x‐www‐form-urlencoded');
data = querystring;
}
xhr.send(data);
}
jQuery中的AJAX(重点)
参考:
$.ajax()(底层接口)
ajax() 方法通过 执行HTTP 请求加载远程数据。
.
a
j
a
x
(
)
返
回
其
创
建
的
X
M
L
H
t
t
p
R
e
q
u
e
s
t
对
象
。
∗
∗
语
法
:
‘
.ajax() 返回其创建的 XMLHttpRequest 对象。 **语法:`
.ajax()返回其创建的XMLHttpRequest对象。∗∗语法:‘.ajax(url[, settings]);`**
- url:一个用来包含发送请求的URL字符串。
- settings:一个以"{键:值}"组成的AJAX 请求设置。所有选项都是可选的。可以使用$.ajaxSetup()设置任何默认参数。
常用选项参数介绍:
- url:请求地址。
- type:请求方法,默认为 get。
- dataType:服务端响应数据类型。
- contentType:请求体内容类型,默认
application/x-www-form-urlencoded
。 - data:需要传递到服务端的数据,如果GET则通过URL传递,如果POST则通过请求体传递。
- timeout:请求超时时间。
- beforeSend:请求发起之前触发(open()之前)。
- success:请求成功之后触发(响应状态码200)。
- error:请求失败触发。返回的是对象。
- complete:请求完成触发(不管成功与否)。
$.ajax({
url: 'get.php', // 请求地址
type: 'get', // method请求方法
data: {id: 1}, // 传递参数
dataType: 'json', // 预期服务器返回的数据类型。用于设置响应体的类型(ContentType)。
beforeSend: function (xhr) {
console.log('before send');
}, // 请求发起之前触发,即在open()之前。
success: function (res) {
console.log(res);
}, // 请求成功拿到的只是响应体,就是readyState=4后的执行函数;会根据Content-Type自动转换res。
error: function (err) {
console.log(err);
}, // 请求失败触发。
complete: function () {
console.log('request completed');
} // 不管成功与否,请求完成触发。
});
$.get()(重要,与$.post()语法一样)
GET 方法可能返回缓存数据。
**$.get() 方法通过 HTTP GET 请求从服务器上请求数据。 **
语法:$.get(URL,data,callback);
$.post()(重要)
POST 方法不会缓存数据,并且常用于连同请求一起发送数据。
**$.post() 方法通过 HTTP POST 请求从服务器上请求数据。 **
语法:$.post(URL,data,callback);
- URL:请求的 URL。
- data:连同请求发送的数据。 即传送的参数。
- callback:请求成功后所执行的函数名。 第一个回调参数存有被请求页面的内容,而第二个参数存有请求的状态。
$("button").click(function(){
$.post("demo_test_post.asp",
{
name:"Donald Duck",
city:"Duckburg"
},
function(data,status){
alert("Data: " + data + "\nStatus: " + status);
});
});
了解
$(selector).load(url[,data][,complete(data,status,xhr)])
- **通过 AJAX 请求从服务器加载数据,并把返回的数据放置到指定的元素中。 **
- complete:请求完成时执行的回调函数。
$.getJSON(url[,data][,success(data,status,xhr)])
- 通过 HTTP GET 请求载入 JSON 数据。 即等价于使用$.ajax()且dataType设置为json。
- url:请求的URL字符串,即地址。
- data:发送给服务器的字符串或Key/value键值对。即参数
- success:当请求成功后执行的回调函数。 response 包含来自请求的结果数据,status 包含请求的状态,xhr 包含 XMLHttpRequest 对象。
$.getScript(url[,success(script,status,xhr)])
- **通过 HTTP GET 请求载入并执行 JavaScript 文件。**即等价于使用$.ajax()且dataType设置为JavaScript。
.ajaxStart(handler())
- 在AJAX 请求刚开始时执行一个处理函数。
.ajaxStop(handler())
- 在AJAX 请求完成时执行一个处理函数。
跨域(重要)
同源策略
同源策略是浏览器的一种安全策略,所谓同源是指域名,协议,端口完全相同,只有同源的地址才可以相互通过 A JAX 的方式请求。 **
同源或者不同源说的是两个地址之间的关系,不同源地址之间请求称为跨域请求 **。
什么是同源?例如:http://www.example.com/detail.html 与一下地址对比
解决跨域请求
JSONP(常用)
JSON with Padding,是一种借助于 script 标签发送跨域请求的技巧。
其原理就是在客户端借助**<script>
标签请求服务端的一个动态网页(php 文件),服务端的这个动态网页返回一段带有函数调用的 JavaScript 全局函数调用的脚本**(header(contentType: application/javascript)),将原本需要返回给客户端的数据传递进去。
例:(jsonp封装)
注意:可能请求有很多次的时候,若都是调用同一函数名会发生覆盖问题,因此要生成多个唯一函数名。
function jsonp(url, params, callback){
var script = document.createElement('script');
// 生成唯一函数名
var funcName = 'jsonp_' + Date.now() + Math.random().toString().substr(2);
window[funcName] = function(data) {
callback(data);
delete window[funcName];
document.body.removechild(script);
}
// 添加参数
if(typeof params === 'object'){
var tempArr = [];
for(var key in params){
var value = params[key];
tempArr.push(key + '=' + value);
}
params = tempArr.join('&');
}
// 请求不同源地址
script.src = url + '?' + params + '&callback' + funcName;
document.body.appendChild(script);
}
<?
$conn = mysqli_connect('localhos','root','123456','demo');
$query = mysqli_query($conn, 'select * from users');
while ($row = mysqli_fetch_assoc($query)) {
$data[] = $row;
}
if(empty($_GET['callback'])){
header('Content-Type: application/json');
echo json_encode($data);
exit();
}
header('Conntent-Type: application/javascript');
$result = json_encode($data);
// 判断客户端给过来的是否为函数
$callback_name = $_GET['callback'];
echo "typeof {$callback_name} === 'function' && {$callback_name}({$result})";
?>
问题:
- JSONP 需要服务端配合,服务端按照客户端的要求返回一段 JavaScript 调用客户端的函数。
- 只能发送 GET 请求。
注意:JSONP 用的是 script 标签,跟A JAX 提供的 XMLHttpRequest 没有任何关系!!!
jQuery使用JSONP
jQuery 中使用 JSONP 就是将 dataType 设置为 jsonp。
$.ajax({
url: '请求不同源地址',
dataType: 'jsonp',
data: {传递参数},
success: function(res){
console.log(res);
}
});
其他常见的 A JAX 封装库:
- Axios
CORS
Cross Origin Resource Share,跨域资源共享。
// 允许远端访问,*可以是其他源
header('Access‐Control‐Allow‐Origin: *');
这种方案无需客户端作出任何变化(客户端不用改代码),只是在被请求的服务端响应的时候添加一个Access Control-Allow-Origin
的响应头,表示这个资源是否允许指定域请求。