网络请求与远程资源
XMLHttpRequest 对象
通过 XMLHttpRequest
构造函数原生支持 XHR 对象
let xhr = new XMLHttpRequest();
使用 XHR
使用 XHR 对象首先要调用 open()
方法,这个方法接收 3 个参数:请求类型、请求URL、请求是否异步的布尔值。
xhr.open("get", "example.php", false);
注意: 只能访问同源 URL,否则会抛出安全错误。
发送定义好的请求,必须调用 send()
方法:
send()
方法接收一个参数,是作为请求体发送的数据。如果不需要发送数据,就必须传入 null。
xhr.open("get", "example.php", false);
xhr.send(null);
收到响应之后, XHR 对象的属性会被填充上数据。
responseText
:作为响应体返回的文本。responseXML
:如果响应的内容类型是 “text/html” 或 “application/xml”,那就是包含响应数据的 XML DOM 文档。status
:响应的 HTTP 状态。statusText
:响应的 HTTP 状态描述。
XMR 对象又有一个 readyState
属性,表示当前处在请求/响应过程的那个阶段。属性的值:
- 0:未初始化。尚未调用
open()
方法。 - 1:已打开。已调用
open()
方法,尚未调用send()
方法。 - 2:已发送。已调用
send()
方法,尚未收到响应。 - 3:接收中。已经收到部分响应。
- 4:完成。已经收到所有响应。
let xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readystate == 4) {
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
console.log(xhr.responseText);
} else {
console.log("unsuccessful", xhr.status);
}
}
};
xhr.open("get", "example.php", true);
xhr.send(null);
在收到响应之前如果想取消异步请求,可以调用 abort()
方法。
HTTP 头部
默认下,XHR 请求会发送以下头部字段
Acceopt
:浏览器可以处理的内容类型。Accept-Charset
:浏览器可以显示的字符集。Accept-Encoding
;浏览器可以处理的压缩编码类型。Accept-Language
:浏览器使用的语言。Connection
:浏览器与服务器的连接类型。Cookie
:页面中设置的 Cookie。Host
:发送请求的页面所在的域。Referer
:发送请求的页面的 URI。User-Agent
:浏览器的用户代理字符串。
如果需要发送额外的请求头部。可以使用 setRequestHeader()
方法。接收两个参数:头部字段的名称和值。必须放在 open()
之后,send()
方法之前。
可以使用 getResponseHeader()
方法从 XHR 对象获取响应头部。传入获取头部的名称即可。
获得所有响应头部,可以使用 getAllResponseHeaders()
方法。
GET 请求
需要在 GET 请求的 URL 后面添加查询字符串参数。查询字符串必须正确编码后添加到 URL 后面,再传入 open()
方法。查询字符串中的每个名和值都必须使用 encodeURIComponent()
编码,所有名/值对必须以 “&” 分隔。
xhr.open("get", "example.php?name=xkc&age=20", true);
URL 添加查询字符串的方法:
function addURLParam(url, name, value) {
url += url.indexOf("?") === -1: "?" : "&";
url += encodeURIComponent(name) + "=" + encodeURIComponent(value);
return url;
}
POST 请求
POST 请求的请求体可以包含非常多的数据。而且数据可以是任意格式。初始化 POST 请求。 open()
方法的第一个参数传入 “post”。
xhr.open("post", "example.php", true);
需要再 send()
方法传入要发送的数据。
XMLHTTPRequest Level 2
FormData 类型
FormData 类型便于表单序列化。
let data = new FormData();
data.append("name", "xkc");
append()
方法接收两个参数:键和值。相对于表单字段名称和字段的值。此外,也可以直接传入一个表单元素。
超时
添加了 timeout
属性。用于表示发送请求后等待多少毫秒,设置一个时间且再该时间过后没有收到响应时,XHR 对象就会触发 timeout
事件。调用 ontimeout
事件处理程序。
let xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readystate == 4) {
try {
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
console.log(xhr.responseText);
} else {
console.log("unsuccessful", xhr.status);
}
} catch (e) {
// 异常处理
console.log(e);
}
}
};
xhr.open("get", "example.php", true);
xhr.timeout = 1000;
xhr.ontimeout = function () {
console.log("没有返回");
}
xhr.send(null);
timeout
属性设置,如果在时间内没有返回,会触发 ontimeout
事件处理程序,readystate
仍然会返回 4,不过超时之后 status
属性会发生错误。
overrideMimeType() 方法
overrideMimeType()
方法用于重写 XHR 响应的 MIME 类型。
进度事件
loadstart
:在接收到响应的第一个字节时触发。progress
:在接收响应期间反复触发。error
:在请求出错时触发。abort
:在调用 abort() 终止连接时触发。load
:在成功接受完响应时触发。loadend
:在通信完成时,且在 error、abort 或 load 之后触发。
load 事件
let xhr = new XMLHttpRequest();
xhr.onload = function () {
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
console.log(xhr.responseText);
} else {
console.log("unsuccessful", xhr.status);
}
};
xhr.open("get", "example.php", true);
xhr.send(null);
progress 事件
在接收数据期间,progress 事件会反复触发。每次触发时,onprogress
事件处理程序都会收到 event 对象。其 target 属性是 XHR 对象,且有 3 个额外属性:lengthComputable
、position
和 totalSize
。lengthComputable
是一个布尔值,表示进度信息是否可用;position
是接收到的字符数;totalSize
是响应的 Content-Length 头部定义的总字符数。拥有这些信息,可以给用户提供进度条,
跨域资源共享
跨域资源共享(CORS)定义了浏览器与服务器如何实现跨域通信。CORS 背后的基本思路是使用自定义的 HTTP 头部允许浏览器和服务器相互了解,以确定请求或响应成功或失败。
跨域 XHR 对象施加额外限制:
- 不能使用
setRequestHeader()
设置自定义头部。 - 不能发送和接收
cookie
。 getAllResponseHeaders()
方法始终返回空字符串。
预检请求
CORS 通过一种叫预检请求的服务器验证机制,允许使用自定义头部、以及不同请求体内容类型。包含头部如下:
Origin
:与简单请求相同。Access-Control-Request-Method
:请求希望使用的方法。Access-Control-Request-Headers
:(可选)要使用的逗号分隔的自定义头部列表。
服务器会响应中发送头部信息:
Access-Control-Allow-Origin
:与简单请求相同。Access-Control-Allow-Methods
:允许的方法。Access-Control-Allow-Headers
:服务器允许的头部。Access-Control-Max-Age
:缓存预检请求的秒数。
替代性跨域技术
图片探测
图片探测是利用 标签实现跨域通信的最早技术。可以跨域加载图片而不必担心限制,可以动态创建图片,然后通过它们的 onload
和 onerror
事件处理程序得知何时收到响应。
let img = new Image();
img.onload = function () {
console.log("load");
};
img.src = "https://www.abcd.com/test?name=xkc";
JSONP
JSONP 格式包含两个部分:回调和数据。回调是在页面接收到响应之后应该调用的函数,通常回调函数的名称是通过请求来动态指定的。数据就是作为参数传入回调函数的 JSON 数据。
http://abcd.com/json/?callback=handleResponse
这个例子中的回调函数名称指定为 handleResponse()
。
JSONP 调用是通过动态创建
function handleResponse(response) {
console.log(response.name, response.age);
}
let script = document.createElement("script");
script,src = "http://abcd.com/json/?callback=handleResponse";
document.body.insertBefore(script, document.body,firstChild);
缺点:
- JSONP 是从不同的域中拉取可执行代码。不安全,一定要保证可信度。
- 不好确定 JSONP 请求是否失败。