Ajax(Asynchronous JavaScript and XML)技术核心是 XMLHttpRequest 对象,能够以异步的方式从服务器获取信息,从而可以不必刷新页面也能获取新数据。即使用 XHR 对象取得新数据,再通过 DOM 操作将新数据插入到页面中。
XHR 的用法
- 创建 XHR 对象
1
var xhr = new XMLHttpRequest();
open()
,初始化请求open(method,url,async)
方法,接受 3 个参数:请求类型,请求的 URL,是否异步(默认为异步请求)send()
,发生请求send(data)
发送请求,接受一个可选参数,作为请求主体发送的数据,如果不需要则必须传入null
abort()
,取消异步请求- 处理响应
在受到响应后,响应的数据会自动填充 XHR 对象的属性- responseText: 作为响应主体被返回的文本
- responseXML: 如果响应的内容类型是”text/xml”,”application/xml”,则改属性保存着包含响应数据的 XML DOM 文档
- status: 响应的 HTTP 状态
- statusText: HTTP 状态说明
在发送异步请求,为了让 JavaScript 继续执行而不必等待响应,可为 XHR 对象添加readystatechange
事件,来在请求/响应过程执行相应动作。XHR 对象的readyState
属性,可表示请求的当前状态,可取值如下:
- 0:UNSENT,为初始化,尚未调用
open()
方法 - 1:OPENED, 启动,已经 调用
open()
方法,但未调用send()
方法 - 2: HEADERS_RECEIVED,发送,已经调用
send()
方法,但尚未接收到响应 - 3: LOADING,接收,已经接收到部分响应数据
- 4: DONE,完成,已经接收到全部响应数据
HTTP 头部信息
setRequestHeader(header, value)
: 设置 HTTP 请求头部,此方法必须在open()
和send()
方法之间调用getResponseHeader(name)
:返回指定的响应头信息getAllResponseHeaders()
: 返回所有响应头
XMLHttpRequest 2
FormData
FormData 类型为序列化表单以及创建与表单格式相同的数据提供了便利。
- 创建 FormData 的 实例后,可直接将它传入 XHR 的
send()
方法 - 另外,XHR 对象能够识别传入的数据类型是 FormData 的实例,并配置适当的头部信息,不需在手动配置头部信息(
shr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded")
)
1 | // 序列化表单 |
超时定时
XHR 对象的timeout
属性,表示请求在等待响应多少毫秒之后终止。
在给 XHRtimeout
设置一个数值后,如果在规定时间内浏览器还没有接收到响应,就会触发timeout
事件.
1 | // ... |
overrideMimeType()
XHR 的overrideMimeType(mimeType)
,指定一个 MIME 类型用于替换服务器指定的类型,使服务器响应信息中传输的数据按照该指定 MIME 类型处理。
注意:如果服务器没有指定一个Content-Type
头,XHR 默认 MIME 类型为"text/xml"
。但如果接收的数据不是有效的 XML,就会出现格式不正确的错误。可用通过overrideMimeType()
指定各种类型来 避免这种情况
进度事件
XHR 对象提供了各种在请求被处理期间发生的事件以供监听,包括定期进度通知,错误通知,完成通知等。具体进度事件如下:
- loadstart: 在接收到响应数据的第一个字节时触发
- progress: 在接收响应数据期间不断触发
- error: 在请求发生错误时触发
- abort: 因调用
abort()
方法而终止连接时触发 - timeout: 请求超时时触发
- load: 在接收到完成数据时触发
- loadend: 通信终止(成功或失败)时触发,error,abort,timeout,load 任意事件后触发
progress 事件
progress 事件在浏览器接收数据期间周期性的触发,其事件处理程序会接收到的 event 对象,具有以下特殊属性
- target: XHR 对象
- lengthComputable: 进度信息是否可用的布尔值,如果为 false,意味着总字节数为止并且 total 的值为 0
- loaded: 已经接收到的字节数
- total: 预计的总字节数
1 | <body> |
跨域资源共享
默认情况下,XHR 对象 只能访问与它包含的页面位于同一域中资源。跨域是指一个域下的文档或脚本试图去请求另一个域下的资源。
广义的跨域
- 资源跳转: a 链接,重定向,表单提交
- 资源嵌入:
<link>
,<script>
,<img>
标签,css 样式中url()
,@font-face()
等文件外链 - 脚本请求: ajax 请求
狭义的跨域
通常所说的跨域是狭义的,是由浏览器同源策略所限制的一类请求场景。同源策略是浏览器最核心的安全功能,所谓同源是指协议+域名+端口三者相同。即使两个不同的域名指向同一 IP 地址,也非同源。
CORS
CORS(Cross-Origin Resource Sharing,跨域资源共享),定义了在必须访问跨域资源时,浏览器与服务器应该如何沟通。其基本思想,就是使用自定义的 HTTP 头部让浏览器与服务器沟通,从而决定请求或响应是成功,还是失败。具体做法如下:
- 浏览器在发生请求时,会给 HTTP 头部附加一个额外的
Origin
头部,其中包含请求页面的源信息(协议+域名+端口),以便服务器根据该头部信息来决定是否响应1
Origin: https://developer.mozilla.org
- 服务器如果认为该请求可以接受,就会在
Access-Control-Allow-Origin
头部中回发相同的源信息,如果是公共资源,可以回发*
1
Access-Control-Allow-Origin: *
- 如果是带凭证的请求,例如 带 cookie 请求时,需要将 XHR 对象
withCredentials
属性设置为 true,如果服务器接收带凭证的请求,会使用 HTTP 头部来响应Access-Control-Allow-Credentials: true
.如果服务器的响应不含该头部,则浏览器不会把响应交给 JavaScript,于是 status 的值为 0,调用 onerror()事件处理程序
跨域解决方案
jsonp
原理:通过动态创建script
,在请求时传参(一个回调函数)给后端,后端在返回时执行这个在前端定义的回调函数,回调函数传入的参数就要返回的数据
前端 代码
1 | <body> |
后端 node.代码
1 | var querystring = require("querystring"); |
postMessage 跨域
postMessage
是 window 属性之一,可安全实现跨域通信,能解决以下问题:
- 页面和其打开的新窗口的数据传递
- 多窗口之间的息传递
- 页面与嵌套的
iframe
之间消息传递
基本思路:一个窗口可以获得对另一个窗口的引用,然后在发送窗口上调用otherWindow.postMessage()
方法分发一个MessageEvent
消息,接收消息的窗口可监听该事件(message
),并可自由处理此事件。
- 分发消息
otherWindow.postMessage(message, targetOrigin)
方法,分发一个消息给targetOrigin
窗口,是通过消息事件对象暴露给接收框口的。- targetWindow: 其他窗口的一个引用,例如,iframe 的
contentWindow
属性,window.open()
返回的窗口对象,命名过或数值索引的winsdow.frames
- message: 要发送给接收窗口的数据,它会被序列化,无需自己序列化
- targetOrigin: 指定那些窗口能接收到消息事件,其值可以是字符串
"*"
,或者一个 URL
- targetWindow: 其他窗口的一个引用,例如,iframe 的
- 接收消息
window.addEventListener("message",receiveMessage)
,通过监听事件来接收消息,事件对象相关属性有:- data: 从其他 window 中传递过来的消息内容
- origin: 调用
postMessage
时发送方窗口的 origin. - source: 对发送消息的窗口对象的引用