Ajax 的基本原理是通过 XMLHttpRequest 对象向服务器发送异步请求,获取服务器返回的数据后,利用 DOM 的操作来更新页面。
——《JavaScript重难点实例精讲》
XMLHttpRequest 对象
{card-list-item}
getAllResponseHeaders()
以字符串的形式返回所有用 CRLF 分隔的响应头,如果没有收到响应,则返回 null
{/card-list-item}
{card-list-item}
getResponseHeader("key")
返回包含指定响应头的字符串,如果响应尚未收到或响应中不存在该报头,则返回 null
{/card-list-item}
{card-list-item}
open(method, url, async, user, password)
初始化一个请求,仅仅配置一些参数,并 不建立 tcp 连接
{/card-list-item}
{card-list-item}
send(blob | arraybuffer | formdata | ...more)
发送请求,异步方法(默认)立即返回,同步方法直到响应到达后才会返回
{/card-list-item}
{card-list-item}
setRequestHeader("key", "value")
设置 HTTP 请求头的值,必须在 open() 之后、send() 之前调用
{/card-list-item}
{/collapse-item}
{collapse-item label="XMLHttpRequest 属性"}
{card-list-item}
readyState
- 0 - 未初始化,XMLHttpRequest 对象已创建
- 1 - open 函数已调用,send 函数未调用
- 2 - send 函数已调用,未收到服务器响应
- 3 - 响应头接收完成,响应体开始接收
- 4 - Http 响应接收完成
{/card-list-item}
{card-list-item}
responseText
返回一个包含对请求响应的 DOMString,如果请求未成功或尚未发送,则返回 null
{/card-list-item}
{card-list-item}
responseXML
返回一个 Document,其中包含该请求的响应,如果请求未成功、尚未发送或是不能被解析为 XML 或 HTML,则返回 null
{/card-list-item}
{card-list-item}
status
HTTP 状态码,如 200 表示成功,404 表示资源未找到
{/card-list-item}
{card-list-item}
statusText
HTTP 状态码的文本表示,200 对应 "OK",404 对应 "Not Found"
{/card-list-item}
{/collapse-item}
XMLHttpRequest 生命周期
- 创建 XMLHttpRequest 对象
- 初始化请求参数
- 发送请求传递数据
处理服务器的响应
// IE7+, Firefox, Chrome, Opera, Safari // IE7 以下的就算了,让他换个浏览器,别费劲了 xhr = new XMLHttpRequest(); xhr.open('post', '/user/profile', true); xhr.setRequestHeader("Content-Type", "text/plain;charset=UTF-8") xhr.onreadystatechange = function() { if (xhr.readyState === 4 && xhr.status === 200) { // do something document.write(xhr.responseText); } else { // do something } } xhr.send("some messsage");
Ajax 新增 7 个进度事件
一个完整的 ajax 请求都会从 loadstart 事件开始,然后不间断地触发 progress 事件,然后触发 load abort timeout 或者 error 事件中的 一个 ,最后触发 loadend 事件
——《JavaScript重难点实例精讲》
- loadstart 在开始接收响应时触发
- progress 在接收响应期间不断触发,直至请求完成
- error 在请求失败时触发
- abort 在主动调用 abort() 函数时触发,表示请求终止
- load 在数据接收完成时触发
- loadend 在通信完成时或者 error abort load 事件后触发
- timeout 在请求超时时触发
xhr.onprogress = function(event) {
event = event || window.event;
if (event.lengthComputable) {
var percentage = (event.loaded / event.total).toFixed(2) * 100;
console.log('持续接收数据:' + percentage + '%');
}
}
Ajax 优点
- 无刷新更新数据
- 异步通信【减少数据传输,降低网络流量,响应迅速】
- 前后端分离
- 前后端负载均衡【前端处理一部分数据逻辑,减轻后端压力】
- 标准化支持【被浏览器广泛支持,技术和机制通用】
Ajax 缺点
- 破坏浏览器正常后退功能
- 安全性问题
- 对 SEO 支持较弱【SEO 屏蔽 JS 代码,而页面是由 JS 生成或依赖 JS,vue react 也有类似问题,不过都有解决方案】
- 违背 URL 唯一资源定位初衷【相同资源 (同一 url) 对应的内容不一致】
Ajax 提交表单
当获取字段较多表单数据时,使用 document 的选择器或 jquery 选择器都有些麻烦,比如:
var username = document.getElementById('username').value();
var email = document.getElementById('email').value();
// ... more form fields
var username = $('#username').val();
var email = $('#email').val();
// ... more form fields
使用 jquery 的 serialize() 函数或者 serializeArray() 序列化 form 表单提交:
$(selector).serialize();
// username=xiaolu&password=12345&telphone=01000000&email=example@qq.com
$(selector).serializeArray();
// [ {name: 'username', value: 'xiaolu'}
// {name: 'password', value: '12345'}
// ...
// ]
此方法固然好,但是不能解决文件上传问题,此时应使用 FormData 对象提交:
var formData = new FormData($('#myForm'));
$.ajax({type:'POST', url: '/user/profile', data: formData})
创建 formdata 实例时可以直接传递表单对象,十分方便!
Ajax 跨域解决方案
出于用户安全的考虑,浏览器的同源策略约定客户端脚本在没有明确授权的情况下,不能读写不同源的目标资源,同源: 协议、域名、端口号 三者完全相同,同源策略有两种表现形式:DOM 同源策略和 xhr 同源策略,前者主要针对 iframe 场景,后者则是 ajax
解决方案一,后端设置 http 请求响应头
// Example for Express
app.all('*', function(req, res, next){
res.header('Access-Control-Allow-Origin', 'http://localhost:8080');
res.header('Access-Control-Allow-Credentials', true);
res.header('Access-Control-Allow-Headers', 'Content-Type');
res.header('Access-Control-Allow-Methods', '*');
next();
});
解决方案二,JSONP
客户端
var buildJSONP = function() {
var studentNo = document.queryuSelector('#studentNo').value;
var param = 'studentNo=' + studentNo + '&callback=successFn';
var url = 'http://localhost:3000/getUserByStudentNo?param';
var script = document.createElement('script');
script.src = url;
document.body.appendChild(script);
}
服务端
app.get('/getUserByStudentNo', function (req, res) {
var studentNo = req.query.callback;
var callbackFn = req.query.callback;
var result = {
studentNo: 1001,
name: 'kingx1',
age: 18
};
var data = JSON.stringfy(result);
res.writeHead('200', { 'Content-Type': 'application/json' });
res.write(callbackFn + '(' + data + ')');
res.write(data);
res.end();
});
JSONP 的优劣
优点:使用简单,不存在兼容问题
缺点:只支持 GET 请求,难以确定请求是否失败
评论 (0)