1. 概述
浏览器与服务器之间,采用 HTTP 协议通信。用户在浏览器地址栏键入一个网址,或者通过网页表单向服务器提交内容,这时浏览器就会向服务器发出 HTTP 请求。
2005年2月,AJAX 这个词第一次正式提出,它是 Asynchronous JavaScript and XML 的缩写,指的是通过 JavaScript 的异步通信,从服务器获取 XML 文档从中提取数据,再更新当前网页的对应部分,而不用刷新整个网页。
后来,AJAX 这个词就成为 JavaScript 脚本发起 HTTP 通信的代名词,也就是说,只要用脚本发起通信,就可以叫做 AJAX 通信。
具体来说,AJAX 包括以下几个步骤。
- 创建 XMLHttpRequest 实例
- 发出 HTTP 请求
- 接收服务器传回的数据
- 更新网页数据
概括起来,就是一句话,AJAX 通过原生的 XMLHttpRequest
对象发出 HTTP 请求,得到服务器返回的数据后,再进行处理。
一旦拿到服务器返回的数据,AJAX 不会刷新整个网页,而是只更新网页里面的相关部分,从而不打断用户正在做的事情。
注意,AJAX 只能向同源网址(协议、域名、端口都相同)发出 HTTP 请求,如果发出跨域请求,就会报错。
2. 如何发请求?(背景)
用 form
可以发请求,但是会刷新页面或新开页面
用 a
可以发 get
请求,但是也会刷新页面或新开页面
用 img
可以发 get
请求,但是只能以图片的形式展示
用 link
可以发 get
请求,但是只能以 CSS、favicon 的形式展示
用 script
可以发 get
请求,但是只能以脚本的形式运行
提出需求:如何不受限制的发请求?
-
get
post
delete
请求都行 - 想以什么形式展示就以什么形式展示
3. 微软的突破
IE 5 率先在 JS 中引入 ActiveX 对象(API),使得 JS 可以直接发起 HTTP 请求。
随后 Mozilla、 Safari、 Opera 也跟进(抄袭)了,取名 XMLHttpRequest
,并被纳入 W3C 规范。
可这样使用XMLHttpRequest:
var x = new XMLHttpRequest()
注意:XMLHttpRequest 是 window下的全局对象
4. AJAX(异步的 JavaScript 和 XML)
Jesse James Garrett 将如下技术点的方案取名叫做 AJAX:异步的 JavaScript 和 XML
- 使用 XMLHttpRequest 发请求
- 服务器返回 XML 格式的字符串(如今用JSON代替了XML)
- JS 解析 XML,并更新局部页面
5. 如何使用 XMLHttpRequest
5.1 XMLHttpRequest对象用法例子
客户端代码:
let request = new XMLHttpRequest(); //创建一个XMLHttpRequest
request.onreadystatechange = function(){
// 通信成功时,状态值为4
if (request.readyState === 4){
if (request.status === 200){
console.log(request.responseText);
} else {
console.error(request.statusText);
}
}
};
request.onerror = function (e) {
console.error(request.statusText);
};
request.open('GET', '/endpoint', true); //配置
request.send(null); //发送
服务器端代码:
if(path === '/'){
response.statusCode = 200
let string = fs.readFileSync('./index.html')
response.setHeader('Content-Type', 'text/html;charset=utf-8')
response.write(string)
response.end()
}
-
http
请求的路径都是绝对路径.所以都是以/
开头 - 设置响应头中的
Content-Type,response.setHeader('Content-Type', 'text/html;charset=utf-8')
,即要求浏览器以HTML的语法解析这段字符串! - 对于HTTP来说,响应的第四部分始终都是字符串,因为
response.write(string)
返回的是字符串,我们给浏览器返回了符合html
格式的字符串。
5.2 XMLHttpRequest 的实例属性
-
XMLHttpRequest.readyState
XMLHttpRequest.readyState
返回一个整数,表示实例对象的当前状态。该属性只读。
4
,表示服务器返回的数据已经完全接收,或者本次接收已经失败。
通信过程中,每当实例对象发生状态变化,它的readyState
属性的值就会改变。
var xhr = new XMLHttpRequest();
if (xhr.readyState === 4) {
// 请求结束,处理服务器返回的数据
} else {
// 显示提示“加载中……”
}
上面代码中,xhr.readyState
等于 4
时,表明脚本发出的 HTTP 请求已经完成。其他情况,都表示 HTTP 请求还在进行中。
-
XMLHttpRequest.onreadystatechange
实例的readyState
属性变化,就会执行这个属性。 -
XMLHttpRequest.responseText
XMLHttpRequest.responseText
属性返回从服务器接收到的字符串,该属性为只读。 -
XMLHttpRequest.status
XMLHttpRequest.status
属性返回一个整数,表示服务器回应的 HTTP 状态码。
基本上,只有2xx和304的状态码,表示服务器返回是正常状态。
if (xhr.readyState === 4) {
if ( (xhr.status >= 200 && xhr.status < 300)
|| (xhr.status === 304) ) {
// 处理服务器的返回数据
} else {
// 出错
}
}
6. 使用JSON解析响应的第四部分
XML语言结构的数据不好用且已经过时了,现使用JSON替代XML。
JSON是一门数据格式化语言,用来表示数据。
JSON官网:JSON
6.1 语法快速过
- JS的数据类型仅剩
symbol
、undefined
、function
没抄 - 铁轨图(从左往右看)
JS VS JSON
undefined 没有
null null
'janice' "janice"
['a','b'] ["a","b"]
{name: 'janice'} {"name":"janice"}
function fn(){} 没有
var a = {} 搞不定(没有变量)
a.self = a 搞不定(没有变量)
{__proto__} 没有原型链
区别:
- JSON没有抄袭
function
和undefined
- JSON的字符串
string
首尾必须是 双引号"
6.2 如何使用JSON
if (path === '/xxx') {
response.statusCode = 200
response.setHeader('Content-Type', 'text/json;charset=utf-8')
response.write(`
{
"note":{
"to": "Rose",
"from": "Jack",
"heading": "经典片段",
"content": "You jump,I jump."
}
}
`)
response.end()
}
服务器返回的是字符串,恰巧这个字符串刚好符合JSON对象的语法格式。
前端收到响应后:
if(request.status >= 200 && request.status < 300){
console.log('说明请求成功')
let string = request.responseText
// 把符合 JSON 语法的字符串转换成 JS 对应的值
let object = window.JSON.parse(string)
// JSON.parse 是浏览器提供的
}else if(request.status >= 400){
console.log('说明请求失败')
}
7. 同源策略
只有 协议+端口+域名 一模一样才允许发 AJAX 请求
- http://baidu.com 可以向 http://www.baidu.com 发 AJAX 请求吗 no
- http://baidu.com:80 可以向 http://baidu.com:81 发 AJAX 请求吗 no
浏览器必须保证:
只有 协议+端口+域名 一模一样才允许发 AJAX 请求
CORS 可以告诉浏览器,我俩一家的,别阻止他
8. CORS 跨域
CORS(Cross-origin resource sharing),全称是“跨域资源共享”,是一个 W3C 标准。它允许浏览器向跨域的服务器,发出 XMLHttpRequest
请求,从而克服了 AJAX 只能同源使用的限制。
在代码中添加CORS头即可跨域:
if (path === '/xxx') {
response.statusCode = 200
response.setHeader('Content-Type', 'text/json;charset=utf-8')
response.setHeader('Access-Control-Allow-Origin', 'http://frank.com:8001')
response.write(`
{
"note":{
"to": "Rose",
"from": "Jack",
"heading": "经典片段",
"content": "You jump,I jump."
}
}
`)
response.end()
}
注意:JSONP不能发起POST请求,要POST只能用CORS
彩蛋
面试问题:请使用原生JS发送Ajax请求
mybutton.addEventListener('click', (e) => {
let request = new XMLHttpRequest()
request.open('get', 'http://jack.com:8002/xxx')
//配置request 参数分别为方法和路径
request.send()
request.onreadystatechange = () => {
if (request.readyState === 4) {
if (request.status >= 200 && request.status < 300) {
// 把符合 JSON 语法的字符串转换成 JS 对应的值
let string = request.responseText
// JSON.parse 是浏览器提供的
let object = window.JSON.parse(string)
console.log(object.note)
} else if (request.status >= 400) {
console.log('请求失败')
}
}
}
})
网友评论