Ajax初识
Web 程序最初的目的就是将信息(数据)放到公共的服务器,让所有网络用户都可以通过浏览器访问
什么是Ajax
- 在此之前,我们可以通过以下几种方式让浏览器发出对服务端的请求,获得服务端的数据:
- 地址栏输入地址,回车,刷新
- 特定元素的 href 或 src 属性
- 表单提交
- 这些方案都是我们无法通过或者很难通过代码的方式进行编程(对服务端发出请求并且接受服务端返回的响应),如果我们可以通过JavaScript直接发送网络请求,那么Web的可能就会更多,随之能够实现的功能也会更多,至少不再是单机游戏
- AJAX(Asynchronous JavaScript and XML),最早出现在 2005 年的 Google Suggest。Ajax是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术。通过在后台与服务器进行少量数据交换,Ajax 可以使网页实现异步更新。这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新。是在浏览器端进行网络编程(发送请求、接收响应)的技术方案,它使我们可以通过js直接获取服务端最新的内容而不必重新加载页面。让 Web 更能接近桌面应用的用户体验。
- 说白了,AJAX就是浏览器提供的一套API,可以通过JavaScript调用,从而实现通过代码控制请求与响应,实现网络编程。
HelloWorld
// 1.xhr类似于浏览器的作用(发送请求接收响应)
const xhr = new XMLHttpRequest();
// 2.打开浏览器 输入网址
xhr.open('GET', 'http://www.baidu.com');
// 3.敲回车键 开始请求
xhr.send();
// 4.等待响应:客户端不知服务端何时才能返回我们需要的响应 -> Ajax API采用事件机制
xhr.onreadystatechange = function() {
// 这个事件并不是只在响应时触发,XHR状态改变就触发 -> 触发3次
if(this.readyState !== 4) return;
// 5.看结果,xhr的responseText获取响应内容(响应体)
console.log(this.responseText);
};
-
涉及到Ajax操作的页面不能使用文件(协议)的方式访问。
-
兼容方案:XMLHttpRequest 在老版本浏览器(IE5/6)中有兼容问题,可以通过另外一种方式代替
const xhr = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP');
同步与异步


-
同步:一个人在同一个时刻只能做一件事情,在执行一些耗时的操作不去做别的事,只是等待
-
异步:在执行一些耗时的操作去做别的事,而不是等待
-
xhr.open()第3个参数可传入一个bool值,作用是设置此次请求是否采用异步方式,默认为异步true:console.log('Pre Ajax...'); var xhr = new XMLHttpRequest(); // 默认第3个参数为true,异步执行 xhr.open('GET', '/user/list', true); xhr.send() xhr.onreadystatechange = function () { if (this.readyState !== 4) return; // 这里的代码最后执行 console.log('Response Done...'); } console.log('Post Ajax...'); -
如果采用同步方式,代码会卡死在
xhr.send()这一步console.log('Pre Ajax...'); var xhr = new XMLHttpRequest(); // 同步方式,第3个参数传入false xhr.open('GET', '/user/list', false); // 【注意】同步需要先注册事件再调用send,否则readystatechange无法触发 xhr.onreadystatechange = function () { if (this.readyState !== 4) return; // 这里的代码最后执行 console.log('Response Done...'); } xhr.send(); console.log('Post Ajax...');
readyState
-
由于 readystatechange 事件是在 xhr 对象状态变化时触发(不单是在得到响应时),也就意味着这个事件会被触发多次,所以我们有必要了解每一个状态值代表的含义
readState 状态描述 说明 0UNSENT 代理(XHR)被创建,但尚未调用 open() 方法 1OPENED open() 方法已经被调用,建立了连接。 2HEADERS_RECEIVED send() 方法已经被调用,并且已经可以获取状态行和响应头 3LOADING 响应体下载中, responseText 属性可能已经包含部分数据 4DONE 响应体下载完成,可以直接使用 responseText -
时间轴:

-
等待响应时,如果需要捕获状态
1的变化,需注意代码执行顺序不要出现来不及的情况) -
一般情况下,加载完成的逻辑我们只处理
readyState=4的情况,此时onreadystatechange事件可以简写成H5当中的onload事件xhr.onload = function () { console.log(this.responseText); }
遵循http
概述
- 本质上 XMLHttpRequest 就是 JavaScript 在 Web 平台中发送 HTTP 请求的手段,所以我们发送出去的请求任然是HTTP 请求,同样符合 HTTP 约定的格式
const xhr = new XMLHttpRequest();
// 设置请求报文的请求行
xhr.open('GET', './mock/user.json');
// 设置请求头
xhr.setRequestHeader('Accept', 'text/plain');
// 设置请求体
xhr.send(null);
xhr.onreadystatechange = function () {
if (this.readyState !== 4) return;
// 获取响应状态码
console.log(this.status);
// 获取响应状态描述
console.log(this.statusText);
// 获取响应头信息
console.log(this.getResponseHeader('Content‐Type'));
console.log(this.getAllResponseHeader()); // 全部响应头
// 获取响应体
console.log(this.responseText); // *文本形式
console.log(this.responseXML); // XML形式,了解即可
}
GET请求
-
在一次 GET 请求过程中,参数传递都是通过 URL 地址中的 ? 参数传递
const xhr = new XMLHttpRequest(); // GET 请求传递参数通常使用的是问号传参 xhr.open('GET', '/user/get?id=3'); // 一般GET请求无需设置响应体,传null或者不传 xhr.send(null); xhr.onreadystatechange = function () { if (this.readyState !== 4) return; console.log(this.responseText); }
POST请求
-
POST 请求过程中,采用请求体承载需要提交的数据
const xhr = new XMLHttpRequest(); // open方法的第一个参数就是设置method xhr.open('POST', '/user/add'); // 设置请求头中的Content‐Type为 application/x‐www‐form‐urlencoded // 标识此次请求的请求体格式为 urlencoded 以便于服务端接收数据 xhr.setRequestHeader('Content‐Type', 'application/x‐www‐form‐urlencoded'); // 需要提交的数据通过send方法传递 // 格式: key1=value1&key2=value2 xhr.send('account=90217&password=123abc'); xhr.onreadystatechange = function () { if (this.readyState !== 4) return; console.log(this.responseText); } -
【注意】一旦请求体是
urlencoded格式,一定要在请求头设置Content-Type为'application/x-www-form-urlencoded'
响应数据格式
XML
- 一种数据描述手段,老掉牙的东西,简单演示一下,不在这里浪费时间,基本现在的项目不用了。
- 淘汰的原因:数据冗余太多
JSON
- 也是一种数据描述手段,类似于 JavaScript 字面量方式。服务端采用 JSON 格式返回数据,客户端按照 JSON 格式解析数据。
- 不管是 JSON 也好,还是 XML,只是在 AJAX 请求过程中用到,并不代表它们之间有必然的联系,它们只是数据协议罢了
response和responseText
this.response:获取到的结果会根据this.responseType的变化而变化this.responseText:获取字符串形式的响应体
模板引擎
处理响应数据渲染
-
模板引擎实际上就是一个 API,模板引擎有很多种,使用方式大同小异,目的为了可以更容易的将数据渲染到HTML
-
使用模板引擎的步骤:
- 选择一个模板引擎
- 下载模板引擎JS文件
- 引入到页面中:
<script src="template-web.js"></script> - 准备一个模板:
<script id="tmpl" type="text/x-art-template">{{模板内容}}</script> - 准备一个数据:
let data = {userList:res.data}; - 过模板引擎的JS提供的一个函数将模板和数据整合得到渲染结果HTML:
var html = template('tmpl', data); - 将渲染结果的HTML设置到默认元素的innerHTML中:
document.getElementById('tbody').innerHTML = html;
-
注意:
- 为什么不在JS变量中写模板 -> 如果将模板写到JS中,维护不方便,不能换行,没有着色
- 为什么使用
script标记 ->script不会显示在界面。
Ajax封装
回调函数
凡是需要得到一个函数内部异步操作的结果,必须使用回调函数,如以下情况:
-
setTimeout, readFile, writeFile, ajax,例子如下:function add(x, y, callback) { // 异步操作(等待1s) setTimeout(function () { let ret = x + y; callback(ret); }, 1000); } add(10, 20, function (ret) { console.log(ret); });
封装Ajax的get方法
function get(url, callback) {
const xhr = new XMLHttpRequest();
xhr.onload = function () {
callback(oReq.responseText); //得到响应的Text
};
xhr.open("get", url, true);
xhr.send();
}
get('data.json', function (data) {
console.log(data);
});
委托
-
函数就可以理解为一个想要做的事情,函数体中约定了这件事情做的过程,直到调用时才开始工作。
-
将函数作为参数传递就像是将一个事情交给别人,这就是委托的概念


封装原生Ajax
/** 封装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)
}
// 调用
ajax('get', './get.php', { id: 123 }, function (data) {
console.log(data)
})
ajax('post', './post.php', { foo: 'posted data' }, function (data) {
console.log(data)
})
jQuery中的Ajax
最基础封装
$.ajax({
// 参数
url: './get.php', // 请求url
type: 'get', // 请求方式
dataType: 'json', // 响应的数据格式
data: { id: 1 }, // 参数
// 回调函数
beforeSend: function (xhr) {// 在请求发生(open和send)之前执行的函数
console.log('before send');
},
success: function (data) { // 请求成功(200)执行的函数
console.log(data);
},
error: function (err) { // 请求失败(非200)的函数
console.log(err);
},
complete: function () { // 只要请求完后就执行的函数
console.log('request completed');
}
});
参数:
-
url:请求地址 -
type:请求方法,默认为 get -
dataType:服务端响应数据类型 -
contentType:请求体内容类型,默认 application/x-www-form-urlencoded -
data:需要传递到服务端的数据,如果 GET 则通过 URL 传递,如果 POST 则通过请求体传递 -
timeout:请求超时时间 -
beforeSend:请求发起之前触发,可以设置请求头,例如:$.ajax({ url: '/user.php', type: 'post', data: {id:1}, success: function(res) { console.log(res); }, beforeSend: function (xhr) { // 发送ajax请求前在Header中携带jwt的tokern认证信息,服务端做校验 xhr.setRequestHeader("Authorization", localStorage.token); }, }) -
success:请求成功之后触发(响应状态码 200) -
error:请求失败触发 -
complete:请求完成触发(不管成功与否)
针对http的进一步封装
-
GET请求:
$.get(url,[data],[callback],[type])$.get('/user.php', {id:1}, function(res) { console.log(res); },'json'); -
POST请求:
$.post(url,[data],[callback],[type])$.post('/user.php', {id:1}, function(res) { console.log(res); }) -
转化为json的GET请求:
// 无论客户端是什么数据类型,接收时都转换为json类型 $.getJSON('/user.php', {id:1}, function(res) { console.log(res); }); -
**缺点:**无法自定义很多回调函数(
error,complete,beforeSend…) -> 只能调用底层的$.ajax -
自学:
$(selector).load()和$.getScript()
Ajax执行时机监听
-
请求开始:
// 只要有Ajax请求发生,就会执行 $(document).ajaxStart(function() { $('.loading').fadeIn(); NProgress.start(); console.log('Ajax start...'); }); -
请求结束:
// 只要有Ajax请求结束,就会执行 $(document).ajaxStop(function() { $('.loading').fadeOut(); NProgress.done(); console.log('Ajax done...'); });
跨域问题及解决
同源及跨域
-
同源:是浏览器的一种安全策略,所谓同源是指域名、协议、端口完全相同,只有同源的地址才可以相互通过Ajax的方式请求。
-
同源策略: 不同源地址之间,默认不能相互发送Ajax请求
-
什么是同源?例如 http://www.example.com/detail.html 与一下地址对比
对比地址 是否同源 原因 http://api.example.com/detail.html 不同源 域名不同 https://www.example.com/detail.html 不同源 协议不同 http://www.example.com:8080/detail.html 不同源 端口不同 http://api.example.com:8080/detail.html 不同源 域名、端口不同 https://api.example.com/detail.html 不同源 协议、域名不同 https://www.example.com:8080/detail.html 不同源 端口、协议不同 http://www.example.com/other.html 同源 只是目录不同 -
**跨域请求:**同源或者不同源说的是两个地址之间的关系,不同源地址之间请求就称之为跨域请求。不同源地址之间如果需要相互请求,必须服务端和客户端配合才能完成。
跨域解决方案
- 注意:
- 其实Ajax可以请求非同源的数据,也能响应,但是浏览器的策略不支持接受数据。
link标签必须有rel属性才能发送请求。script标签只能发get请求,不能发post请求,所以传参只能是url中的?之后。
- img标签:可以发送不同源地址之间的请求,但无法拿到响应结果
config img = new Image(); img.src = 'https://www.bjtu.edu.cn/images/img2019/logo_01.png';
- link标签:可以发送不同源地址之间的请求,但无法拿到响应结果
const link = document.createElement('link'); // link标签必须写rel属性才能发请求 link.rel = 'stylesheet'; link.href = 'http://locally.uieee.com/categories'; document.body.appendChild(link); - script标签:可以发送不同源地址之间的请求,无法拿到响应结果。但可借助于能够作为JS执行
const script = document.createElement('script'); script.src = 'http://localhost/time2.php'; // 开始发起请求 document.body.appendChild(script); // 相当于请求的回调 function foo(res){ console.log(res); }
jsonp
-
因为XMLHttpRequest 无法发送不同源地址之间的跨域请求,所以可借助script标签进行跨域请求,这种方式称为jsonp(JSON with Padding)。其原理就是在客户端借助 script 标签请求服务端的一个动态网页(php 文件),服务端的这个动态网页返回一段带有函数调用的 JavaScript 全局函数调用的脚本,将原本需要返回给客户端的数据传递进去。
-
客户端:http://www.zce.me/users-list.html
<script src="http://api.zce.me/users.php?callback=foo"></script> -
服务端:http://api.zce.me/users.php?callback=foo
foo(['我', '是', '你', '原', '本', '需', '要', '的', '数', '据']) -
缺点:1. JSONP 需要服务端配合,服务端按照客户端的要求返回一段 JavaScript 调用客户端的函数;2.只能发送 GET 请求
-
jQuery 中使用 jsonp 就是将
dataType设置为'jsonp':// jQuery的封装 $.ajax({ url: 'http://localhost/jsonp/server.php', // 指定此参数,直接发送jsonp请求 dataType: 'jsonp', success: function (res) { console.log(res); } });
CORS
-
Cross Origin Resource Share,跨域资源共享,一行代码解决跨域请求。这种方案无需客户端作出任何变化、不用改代码,只是在被请求的服务端响应时添加
Access-Control-Allow-Origin响应头,表示这个资源是否允许指定域请求 -
**语法:**服务端php文件
// 允许远端访问 header('Access‐Control‐Allow‐Origin: *');
XMLHttpRequest 2.0
更易用,更强大;暂作了解,无需着重看待
Ajax渲染
- 优点:性能更好,提高用户体验
- 缺点:不利于seo,搜索引擎收录的网页源码。
- 解决方案:同时会去更改地址栏,注意地址栏在服务端一定有对应的页面
onload / onprogress
const xhr = new XMLHttpRequest();
xhr.open('GET', './time.php');
xhr.send();
xhr.onload = function () {
// onload readyState === 4
console.log(this.readyState);
}
xhr.onprogress = function () {
// onload readyState === 3
console.log(this.readyState);
}
FormData
- 以前 AJAX 只能提交字符串,现在可以提交二进制数据

被折叠的 条评论
为什么被折叠?



