Ajax
Asynchronous JavaScript and XML,通过JavaScript异步通信,从服务器获取XML文档(JSON 格式数据)并从中提取数据,再更新当前网页的对应部分,而不用刷新整个网页。
- 创建XMLHttpRequest实例
- 发出HTTP请求
- 接收服务器传回的数据
- 更新网页数据
注意,AJAX只能向同源网址(协议、域名、端口都相同)发出HTTP请求,如果发出跨域请求,就会报错。
缺点:同源限制。
readyState
表示实例对象的当前状态,只读。
- 0,请求未初始化,表示 XMLHttpRequest 实例已经生成,但是实例的
open()
方法还没有被调用。 - 1,服务器连接已建立,表示
open()
方法已经调用,但是实例的send()
方法还没有调用,仍然可以使用实例的setRequestHeader()
方法,设定 HTTP 请求的头信息。 - 2,请求已接受,表示实例的
send()
方法已经调用,并且服务器返回的头信息和状态码已经收到。 - 3,请求处理中,表示正在接收服务器传来的数据体(body部分)。这时,如果实例的
responseType
属性等于text
或者空字符串,responseText
属性就会包含已经收到的部分信息。 - 4,请求已完成且响应已就绪,表示服务器返回的数据已经完全接收,或者本次接收已经失败。
xhr.onreadystatechange = function(){ /// 通信成功 if (xhr.readyState === 4){ /// 获取数据成功 if (xhr.status === 200){ console.log(xhr.responseText); } else { console.error(xhr.statusText); } } };
status
表示服务器回应的 HTTP 状态码。
- 200, OK,访问正常
- 403, Forbidden,禁止访问
- 404, Not Found,未发现指定网址
- 500, Internal Server Error,服务器发生错误
另外,statusText属性返回一个字符串,表示服务器发送的状态提示。
upload
主要用于追踪文件上传的进度。
该属性得到一个对象,通过该对象的onprogress上的监听函数可以得知上传的进展。
function updateProgress (evt) { if (evt.lengthComputable) { var percentComplete = evt.loaded / evt.total; } }
getAllResponseHeaders()
收到服务器响应后,获取服务器发来的所有 HTTP 头信息。
返回值为字符串,每个头信息之间使用CRLF
分隔(回车+换行)[\r\n]
/// 获取 var headers = xhr.getAllResponseHeaders(); /// 处理 var arr = headers.trim().split(/[\r\n]+/); var headerMap = {}; arr.forEach(function (line) { var parts = line.split(': '); var header = parts.shift(); var value = parts.join(': '); headerMap[header] = value; });
abort()
终止已经发出的 HTTP 请求。调用方法后,readyState属性变为4,status属性变为0。
if (xhr) { xhr.abort(); xhr = null; }
onreadyStateChange VS onload
- load事件表示请求成功完成,服务器传来的数据接收完毕,即只有状态码为4时才回调一次函数。
- onreadystatechange表示只要返回的状态码发生变化就回调一次函数。
文件上传
HTML网页的<form>元素支持四种格式,向服务器发送数据:
- POST方法,enctype=application/x-www-form-urlencoded,默认方法
- POST方法,enctype=text/plain
- POST方法,enctype=multipart/form-data
- GET方法,enctype属性忽略
通常使用file控件上传文件,控件的multiple属性,标识可以一次选择多个文件。
<input type="file" id='input-file-select' name='input-file-name' multiple/> /// 获取选中待传文件 var fileSelect = document.getElementById('input-file-select'); var files = fileSelect.files; /// 组装FormData对象 var formData = new FormData(); files.forEach(function (file) { formData.append('input-file-name', file, file.name); });
除了使用FormData上传,也可以直接使用File API上传
var xhr = new XMLHttpRequest(); xhr.open('POST', myURL); xhr.setRequestHeader('Content-Type', file.type); xhr.send(file);
Ajax同源问题
除了服务器代理(浏览器请求同源服务器,再由后者请求外部服务),支持三种方法规避限制
[1]. JSONP
服务器与客户端跨源通信的常用方法,简单适用,服务端改造非常小。
缺点:只能发Get请求。但是,支持老式浏览器,可以向不支持CORS的网站请求数据。
基本思想:网页通过添加一个<script>元素,向服务器请求JSON数据,不受同源政策限制;服务器收到请求后,将数据放在一个指定名字的回调函数里传回来。
[2]. WebSocket
一种使用 ws://(非加密)和 wss://(加密)作为协议前缀的通信协议,不实行同源政策。
优点:允许服务器端与客户端进行全双工(full-duplex)的通信。(HTTP仅支持客户端请求服务器)
WebSocket握手,建立在 TCP 协议之上。
[3]. CORS
跨源资源分享(Cross-Origin Resource Sharing),W3C标准, 跨源Ajax请求的 根本解决 方法。
- 与JSONP相比,支持任何类型的请求
- 整个CORS通信过程,浏览器自动完成
CORS请求分成两类
- 简单请求:同表单请求
- 非简单请求:先预检请求,不通过则提前拒绝,通过则正常请求