本文目前为止只是个概述笔记,原文是个系列文章,链接在最后的参考部分,写得非常好,强烈推荐。
AJAX 是什么
Asynchronous JavaScript And XML
xml 和 json
- 最初互联网数据都是通过 xml(可扩展标记语言)传输的
- 后来 json 巨多,json 只是数据
- xml 是语言,依旧有自己的优势场景
目的 -> 无页面刷新获取服务端数据
是一种混合技术 -> JS、客户端、服务端
- JS,用于获取数据后以操作 DOM 或其它方式达成目标
- 客户端(即浏览器),提供 XMLHttpRequest 对象
- 服务端,拥有允许客户端向其发起 AJAX 请求的相关设置
使用 AJAX
怎样通过 JS 发送 AJAX 请求?
核心:XMLHttpRequest 对象 (构造函数)
方法
-
.open()
准备启动一个 AJAX 请求 -
.setRequestHeader()
设置请求头部信息 -
.send()
发送 AJAX 请求 -
.getResponseHeader()
获取响应头部信息 -
.getAllResponseHeader()
获取一个包含所有响应头部信息的长字符串 -
.abort()
取消异步请求
属性
-
.responseText
响应返回的主体文本 -
.responseXML
响应内容类型为text/xml
或application/xml
时,该属性包含响应返回的 XML DOM 文档 -
.status
响应的 HTTP 状态 -
.statusText
HTTP 状态的说明 -
.readyState
表示“请求/响应”过程的当前活动阶段
监听事件
-
.onreadystatechange()
监听readyState
的变化
使用流程?
准备 open()
- get/post
- url ,查询参数
注意:参数的名和值都需要 encodeURIComponent 进行编码
注意:若 url 为相对地址,应该是相对于执行此代码的页面
- 同步/异步
设置请求头
- 默认的请求头
- setRequestHeader()
注意部分浏览器不允许重写默认的请求头,因此自定义请求头是比较安全的做法
发送数据
- get -> send(null)
注意:send 必须有参数,所以需要传个 null
- post -> send(data)
处理响应
- 异步 onreadystatechange readystate 0/1/2/3/4
注意,事件处理函数写在 .open() 前(以保证浏览器兼容性)
取消异步请求
- xhr.abort()
注意,取消后要手动给 xhr 解绑(xhr = null)以释放内存
XMLHttpRequest 二级
在之前的基础上,W3C 提出了 XMLHttpRequest 二级规范,但是并不是所有浏览器都实现了,介绍一些被全部或多数浏览器实现的功能。
FormData 类型
超时设定
- timeout
- ontimeout
注意,超时后请求中止,会调用 ontimeout,但此时有可能 readyState 已经变为4,这意味着会继续调用 onreadystatechange,但是当超时请求中止后再访问 status 属性浏览器会报错误,因此需要将检查 status 的语句放入 try catch 中
overrideMimeType() 方法
进度事件
- onloadstart
- onprogress
- onerror
- onabort
- onload
- onloadend
跨域问题
缘起?同源策略
AJAX 使数据传输变得方便,但是对于某些数据,隐私和安全需要重视,因此有了同源策略,来进行能力限制。
浏览器的同源策略:限制不同源之间执行特定操作。
- 一个源由协议、域名和端口三部分组成,三者中任一一个不同,都会被浏览器认为是不同的源。
- 特定的操作是指:
- 读取 Cookie、LocalStorage 和 IndexDB
- 获取 DOM 元素
- 发送 AJAX 请求
为什么要限制这些特定操作
- 很多网站会把用户名密码之类的数据存放到 Cookie,如果没有同源策略,我们就可以通过 JS 脚本读取到浏览器里存储的所有网站的 Cookie,有了同源策略,我们只能读取到自己的网站域名下的 Cookie,相当于只能读取自己设置的。
- 如果能够获取其它源下的 DOM,那么利用 iframe 标签引入其它网站内容,诱导用户操作表单,由于能够获取其它站点的 DOM,就可以监听和操作 DOM,例如可以获取用户输入的密码。
- 为什么要禁止发送 AJAX 请求呢?这和 Cookie 的运作原理有关。每一条 Cookie 都由 domain 和 path 两个属性来标识它所属的源,当浏览器发送 Http 请求时,它会自动查找与请求 URL 匹配的 Cookie,如果有,就会自动加入到 header 头的 Cookie 属性中发送出去,服务器返回信息,会原封不动地把这个 Cookie 内容加到返回头里传回来。嗅到危险了吗?如果没有同源策略,我们在自己的服务器上托管网站 A,在 A 网站被访问时,运行我们的脚本,脚本向 B 网站(比如是个银行网站)发送一个请求,如果这个用户的浏览器恰好保存有 B 网站的 Cookie,那么我们就可以通过请求的返回头拿到这个 Cookie 了。
同源策略的表现
- JS 读取 Cookie 等只能读到自己所在域的数据。
- iframe 标签里只显示一个空空的 #document 节点。
- 对于跨域的 AJAX 请求,在响应返回时,浏览器识别出来给拦下,只报个错误出来告诉跨域了。
跨域解决方案
(一)JSONP - 野路子出身却异常好用
- JSON with padding,包裹的 json
- 原理就是不用 AJAX 了,用 script 标签来达到目的。script 标签不受跨域限制,加载进来的脚本就会立即执行。怎么实现呢?来看客户端的用法:
function handleResponse(response){
alert(`You got the response data: ${response}`)
}
const script = document.createElement('script')
script.src = 'http://somesite.com/json/?callback=handleResponse'
document.body.insertBefore(script, document.body.firstChild)
- 是不是迷惑了?response 到底是怎样拿到的?别急,关键的部分就在服务器了:服务器识别 url 解析出 callback 的函数名 handleResponse,然后把需要返回的 json 数据作为参数传入 handleResponse,把执行这个函数语句作为响应返回给浏览器。
- 浏览器加载到这个脚本后直接执行,就弹出了 response 的内容了。
- 是不是很巧妙呢,JSONP,这个 padding 原来就是我们的 callback 函数。
(二)CORS - 官方推荐的跨域资源共享方案
(坑,待填)
(三)使用 HTML5 API:postMessage
(坑,待填)
(四)抛弃 HTTP,使用:Web Sockets
(坑,待填)
参考
再也不学AJAX了!(一)AJAX概述
再也不学AJAX了!(二)使用AJAX
再也不学AJAX了!(三)跨域获取资源 ① - 同源策略
再也不学AJAX了!(三)跨域获取资源 ② - JSONP & CORS
再也不学AJAX了!(三)跨域获取资源 ③ - WebSocket & postMessage
网友评论