一、原生 AJAX
1. AJAX 简介
AJAX,即 Asynchronous JavaScript and XML 的缩写,指的是通过 JavaScript 的异步通信,从服务器获取 XML 文档从中提取数据,再更新当前网页的对应部分,而 不用刷新整个网页。
后来,AJAX 这个词就成为 JavaScript 脚本发起 HTTP 通信的代名词,也就是说,只要用脚本发起通信,就可以叫做 AJAX 通信。
AJAX 不是新的编程语言,而是一种将现有的标准组合在一起使用的新方式。
具体来说,AJAX 包括以下几个步骤:
概况来说,AJAX 通过原生的 XMLHttpRequest 对象发出 HTTP 请求,得到服务器返回的数据后,再进行处理 。
?
2. XML 简介
XML 可扩展标记语言,是一种用于标记电子文件使其具有结构性的标记语言。XML 被用于存储和传输数据。
XML 和 HTML 类似,不同的是 HTML 中都是预定义标签,而 XML 中没有预定义标签,全都是自定义标签,用来表示一些数据。
例如,对于一个学生数据 name = "孙悟空" ; age = 18; gender = "男" 可以用 XML 表示为
<student>
<name>孙悟空</name>
<age>18</age>
<gender>男</gender>
</student>
现在,服务器返回的都是 JSON 格式的数据,XML 格式已经被 JSON 取代了。JSON 表示为
{"name":"孙悟空", "age":18, "gender":"男"}
?
3. AJAX 特点
- 可以在页面不刷新的情况下,向服务端发送请求
- 允许根据用户事件(如鼠标事件、键盘事件、表单事件等)来更新部分页面内容
- 没有浏览历史,不能回退
- 存在跨域问题(同源)。如
a.com 网页打算向 b.com 网页发送请求,Ajax 默认是不允许的。 - SEO 搜索引擎优化不友好,爬虫爬取不到网页中相关数据
?
4. XMLHttpRequest 对象
AJAX 的核心是 XMLHttpRequest 对象。它用于同幕后服务器交换数据,这意味着可以更新网页的部分,而不需要重新加载整个页面。
const xhr = new XMLHttpRequest();
先简单进行列举,后文用到时详解。
先简单进行列举,后文用到时详解。 ?
5. 向服务器发送请求
如需向服务器发送请求,我们使用 XMLHttpRequest 对象的 open() 和 send() 方法。如下:
- GET 请求
xhr.open('GET', 'http://127.0.0.1:8000/server');
xhr.send();
- POST 请求
xhr.open('POST', 'http://127.0.0.1:8000/server');
xhr.send();
如需像 HTML 表单那样 POST 数据,需要通过 setRequestHeader() 添加一个 HTTP 头部。
xhr.open('POST', 'http://127.0.0.1:8000/server');
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.send('a=100&b=200&c=300');
初始化 HTTP 请求参数,但不会发送请求。
xhr.open(method, url [, async][,user][,pwd])
method :要使用的 HTTP 方法,比如 GET 、POST 等。url :要向其发送请求的 URL 。async :可选,表示是否异步执行操作,默认为 true 。true 表示通过异步发送请求;false 表示同步发送请求,将停止执行直到服务器响应就绪(不推荐使用)。user :可选,用户名称。pwd :可选,密码。
这个方法导致一个 HTTP 请求发送。
xhr.send(body)
GET 请求不传 body 参数,只有 POST 请求使用。
如果之前没有调用 open() ,或者更具体地说,如果 readyState 不是 1,send() 抛出一个异常。否则,它发送一个 HTTP 请求,该请求由以下几部分组成:
- 之前调用
open() 时指定的 HTTP 方法、URL 以及认证资格(如果有的话)。 - 之前调用
setRequestHeader() 时指定的请求头部(如果有的话)。 - 传递给这个方法的 body 参数。
向请求添加 HTTP 头部,也就是设置请求头信息。此方法必须在 open() 方法和 send() 之间调用。
setRequestHeader(header, value)
- header:规定头部名称
- value:规定头部值
一般我们设置的是:content-type,传输数据类型,即服务器需要我们传送的数据类型
xhr.setRequestHeader ("content-type", "application/x-www-form-urlencoded" )
?
6. 接收服务器响应
readyState 保存了 XMLHttpRequest 的状态。其属性值对应描述如下:
属性值 | 描述 |
---|
0 | XMLHttpRequest 对象已创建或已被 abort() 方法重置 | 1 | open() 方法已调用, send() 方法未调用。请求还没有被发送 | 2 | send() 方法已调用,HTTP 请求已发送到 Web 服务器,但还未接收到响应 | 3 | 所有响应头部都已经接收到,响应体开始接收但未完成 | 4 | 请求已完成且 HTTP 响应已经完全接收 |
每当 readyState 发生变化时就会调用 onreadystatechange 函数。
请求的状态码,HTTP 响应中状态行的一部分。不同的状态码代表不同的含义,如下:
状态码 | 描述 |
---|
1xx | 表示 HTTP 请求已经接受,继续处理请求 | 2xx | 表示 HTTP 请求已经处理完成 | 3xx | 表示把请求访问的 URL 重定向到其他目录 | 4xx | 表示客户端出现错误 | 5xx | 表示服务器端出现错误 |
常用的状态码:
状态码 | 描述 |
---|
200 | 表明该请求被成功地完成,所请求的资源发送回客户端 | 403 | Forbidden 禁止访问 | 404 | Not Found 资源不存在 |
onreadystatechange 属性定义当 readyState 发生变化时执行的函数。
看下面示例。
xhr.onreadystatechange = () => {
if (xhr.readyState === 4) {
if (xhr.status >= 200 && xhr.status < 300) {
document.querySelector('div').innerHTML = xhr.response;
}
}
}
如上代码表示:当可以成功访问且有响应时,将响应信息写入到 div 中。
XMLHttpRequest 属性 responseType 是一个枚举字符串值,用于指定响应中包含的数据类型。它还允许作者更改响应类型。如果将 responseType 的值设置为空字符串,则会使用 text 作为默认值。
值 | 描述 |
---|
"" | 与默认类型 “text” 相同 | "arraybuffer" | response 是一个包含二进制数据的 JavaScript ArrayBuffer | "blob" | response 是一个包含二进制数据的 Blob 对象 | "document" | response 是一个 HTML Document 或 XML XMLDocument,根据接收到的数据的 MIME 类型而定。 | "text" | response 是 DOMString 对象中的文本 | "json" | response 是通过将接收到的数据内容解析为 JSON 而创建的 JavaScript 对象 |
如下示例,设置响应体数据类型为 json
xhr.responseType = 'json';
xhr.onreadystatechange = () => {
if (xhr.readyState === 4) {
if (xhr.status >= 200 && xhr.status < 300) {
result.innerHTML = xhr.response.name;
}
}
}
当然,你也可以手动对数据进行转换,只不过显得有些麻烦。如下
let data = JSON.parse(xhr.response);
result.innerHTML = data.name;
?
7. AJAX 的使用
下图表示 AJAX 工作流程:
下面两个示例,分别为向服务器发送 GET 和 POST 请求。
需求:点击按钮,向服务端发送 GET 请求;响应结果在 div 呈现
前端页面 index.html
<button>点击发送请求</button>
<div id="result"></div>
<script>
const btn = document.querySelector('button');
const result = document.querySelector('#result');
btn.addEventListener('click', () => {
const xhr = new XMLHttpRequest();
xhr.open('GET', 'http://127.0.0.1:8000/server');
xhr.send();
xhr.onreadystatechange = () => {
if (xhr.readyState === 4) {
if (xhr.status >= 200 && xhr.status < 300) {
result.innerHTML = xhr.response;
} else {
}
}
}
})
</script>
服务器端 sever.js
const express = require('express');
const app = express();
app.get('/sever', (req, res) => {
res.setHeader('Access-Control-Allow-Origin', '*');
res.send('Hello AJAX');
})
app.listen(8000, () => {
console.log('服务已经启动, 8000 端口监听中...');
})
前端页面 index.html
<div id="result"></div>
<script>
const result = document.querySelector('#result');
result.addEventListener('mouseenter', function () {
const xhr = new XMLHttpRequest();
xhr.open('POST', 'http://127.0.0.1:8000/server');
xhr.send();
xhr.onreadystatechange = () => {
if (xhr.readyState === 4) {
if (xhr.status >= 200 && xhr.status < 300) {
result.innerHTML = xhr.response;
}
}
}
})
</script>
服务器端 sever.js
const express = require('express');
const app = express();
app.post('/sever', (req, res) => {
res.setHeader('Access-Control-Allow-Origin', '*');
res.send('Hello AJAX POST');
})
app.listen(8000, () => {
console.log('服务已经启动, 8000 端口监听中...');
})
?
8. 请求超时与网络异常处理
我们可以使用一个超时设置来设置一个时间,到时自动取消请求。进而避免代码为了等候读取请求的返回数据长时间执行。
超时毫秒数可以通过为 XMLHttpRequest 对象的 timeout 属性赋值来指定:
xhr.timeout = 2000;
同时还可以为 timeout 事件的 ontimeout 事件句柄指定事件处理函数,如下:
xhr.ontimeout = () => {
alert('请求超时,稍后重试');
}
XMLHttpRequestEventTarget.onerror 是 XMLHttpRequest 事务由于错误而失败时调用的函数。
请注意只有在网络层级出现错误时才会调用此函数。如果错误只出现在应用层(比如发送一个HTTP的错误码),这个方法将不会被调用。
xhr.onerror = () => {
alert('你的网络似乎除了一些问题');
}
注意:可以通过下面操作设置断网
?
9. AJAX 取消请求
XMLHttpRequest.abort() 方法:如果该请求已被发出,利用此方法将终止该请求。
如下所示:
const btns = document.querySelectorAll('button');
let xhr = null;
btns[0].addEventListener('click', () => {
xhr = new XMLHttpRequest();
xhr.open('GET', 'http://127.0.0.1:8000/delay');
xhr.send();
})
btns[1].addEventListener('click', () => {
xhr.abort();
})
如果同意请求被重复发送,会使得服务器压力比较大,效率变低的问题。
解决方法:创建标识变量,通过标识变量判断此前的请求是否已经完成,未完成则利用 abort() 取消此次请求。
const btn = document.querySelector('button');
let xhr = null;
let isSending = false;
btn.addEventListener('click', () => {
if (isSending) x.abort();
xhr = new XMLHttpRequest();
isSending = true;
xhr.open('GET', 'http://127.0.0.1:8000/delay');
xhr.send();
xhr.onreadystatechange = () => {
if (xhr.readyState === 4) {
isSending = false;
}
}
})
?
二、jQuery 中 AJAX 请求
详细内容可查阅文档 :jQuery API - AJAX
1. $.ajax()
通过 HTTP 请求加载远程数据。这是 jQuery 底层 AJAX 实现。简单易用的高层实现见 $.get ,$.post 等。
$.ajax() 返回其创建的 XMLHttpRequest 对象。
$.ajax(url,[settings])
url :一个用来包含发送请求的 URL 字符串。settings :AJAX 请求设置。所有选项都是可选的。
可选的选项有很多,这里简单列举一些常用的作为说明。
data :发送到服务器的数据。将自动转换为请求字符串格式。dataType :指定服务器返回的数据类型。如,xml 、html 、json 、script 、text type :请求方式。默认 GET 请求,也可以设置为 POST。注意:其他 HTTP 请求方法,如 PUT 和 DELETE 也可以使用,但仅部分浏览器支持。timeout :设置请求超时时间。headers :设置头信息。async :(默认: true) 默认设置下,所有请求均为异步请求。如果需要发送同步请求,请将此选项设置为 false。
除此外,还有几种回调函数可作为参数选项
beforeSend(XHR) :发送请求前可修改 XMLHttpRequest 对象的函数,如添加自定义 HTTP 头。XMLHttpRequest 对象是唯一的参数。success(data, textStatus, jqXHR) :请求成功后的回调函数。参数:由服务器返回,并根据 dataType 参数进行处理后的数据;描述状态的字符串。还有 jqXHR(在jQuery 1.4.x的中,XMLHttpRequest) 对象 。在jQuery 1.5, 成功设置可以接受一个函数数组。每个函数将被依次调用。error :请求失败时调用此函数。有以下三个参数:XMLHttpRequest 对象、错误信息、(可选)捕获的异常对象。如果发生了错误,错误信息(第二个参数)除了得到null之外,还可能是 "timeout" ,"error" ,"notmodified" 和 "parsererror" 。complete(XHR, TS) :请求完成后回调函数 (请求成功或失败之后均调用)。参数: XMLHttpRequest 对象和一个描述成功请求类型的字符串。
$('button').eq(2).click(() => {
$.ajax({
url: 'http://127.0.0.1:8000/jquery-server',
data: { a: 100, b: 200 },
type: 'GET',
dataType: 'json',
success: (data) => {
console.log(data);
},
timeout: 2000,
error: () => {
console.log('出错啦.....');
},
headers: {
c: 300,
d: 400
}
});
})
?
2. $.get
通过远程 HTTP GET 请求载入信息。请求成功时可调用回调函数。如果需要在出错时执行函数,请使用 $.ajax 。
$.get(url, [data], [callback], [type])
url :请求的 URL 地址。data :请求携带的参数。callback :载入成功时回调函数。可以接收响应体参数(data )。type :设置响应体类型。如,xml , html , script , json , text , _default 。
请求 test.php 网页,忽略返回值。
$.get("test.php");
请求 test.php 网页,传送 2 个参数,忽略返回值。
$.get("test.php", { name: "John", time: "2pm" } );
请求 http://127.0.0.1:8000/jquery-server 网页,传送 2 个参数,添加回调,成功时打印以 json 格式打印回调信息。
$('button').eq(0).click(() => {
$.get('http://127.0.0.1:8000/jquery-server', {
a: 100,
b: 200
}, (data) => {
console.log(data);
}, 'json');
})
?
3. $.post
和 GET 请求相似。通过远程 HTTP POST 请求载入信息。
$.post(url, [data], [callback], [type])
url :请求的 URL 地址。data :请求携带的参数。callback :载入成功时回调函数。type :设置返回内容格式,xml , html , script , json , text , _default 。
$('button').eq(1).click(() => {
$.post('http://127.0.0.1:8000/jquery-server', {
a: 100,
b: 200
}, (data) => {
console.log(data);
});
})
?
三、axios 发送 AJAX 请求
官方文档:axios 中文文档
Axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中。简单的讲就是可以发送 GET、POST 请求。 ?
1. axios 特性
- 从浏览器中创建 XMLHttpRequests
- 从 node.js 创建 http 请求
- 支持 Promise API
- 拦截请求和响应
- 转换请求数据和响应数据
- 取消请求
- 自动转换 JSON 数据
- 客户端支持防御 XSRF
?
2. axios 安装
$ npm install axios
$ bower install axios
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
?
3. axios 使用
axios.defaults.baseURL = 'http://127.0.0.1:8000';
btns[0].onclick = function () {
axios.get('/axios-server', {
params: {
id: 100,
vip: 7
},
headers: {
name: 'zs',
age: 18
}
}).then(value => {
console.log(value);
});
}
想要处理返回结果,后面跟 then() 方法处理即可。
axios.post(url[, data[, config]])
示例
axios.post('/axios-server', {
username: 'admin',
password: 'admin'
}, {
params: {
id: 200,
vip: 9
},
headers: {
height: 180,
weight: 170
}
})
可以通过向 axios 传递相关配置来创建请求。
axios(config)
示例如下
axios({
method: 'POST',
url: '/axios-server',
params: {
vip: 10,
level: 30
},
headers: {
a: 100,
b: 200
},
data: {
username: 'admin',
password: 'admin'
}
}).then(response => {
console.log(response.status);
console.log(response.statusText);
console.log(response.headers);
console.log(response.data);
})
?
四、fetch 发送 AJAX 请求
fetch() 方法用于发起获取资源的请求。它返回一个 Promise,这个 Promise 会在请求响应后被 resolve,并传回 Response 对象。
fetch() 方法的参数与 Request() 构造器是一样的。
fetch('http://127.0.0.1:8000/fetch-server', {
method: 'POST',
headers: {
name: 'zs'
},
body: 'username=admin&password=admin'
}).then(response => {
return response.text();
}).then(response => {
console.log(response);
});
参考:
1) W3school - AJAX 教程
2)【尚硅谷】3小时 Ajax 入门到精通
|