AJAX即“Asynchronous JavaScript and XML”,javascript异步处理网络请求是现在更好理解的说法。
XMLHttpRequest XHR
XMLHttpRequest 运行步骤
- 创建XHLHttpRequest
- 使用xhr.open()初始化该xhr
- xhr.send()发送请求
- 监听xhr事件,通常是onload,onerror,onprogress
xhr发起get/post请求的一段代码
// 1. 创建一个 new XMLHttpRequest 对象
let xhr = new XMLHttpRequest();
// 2. 配置它:从 URL /article/.../load GET-request
xhr.open('GET', '/article/xmlhttprequest/example/load');
// 3. 通过网络发送请求
xhr.send();
// 4. 当接收到响应后,将调用此函数
xhr.onload = function() {
if (xhr.status != 200) { // 分析响应的 HTTP 状态
alert(`Error ${xhr.status}: ${xhr.statusText}`); // 例如 404: Not Found
} else { // 显示结果
alert(`Done, got ${xhr.response.length} bytes`); // response 是服务器响应
}
};
xhr.onprogress = function(event) {
if (event.lengthComputable) {
alert(`Received ${event.loaded} of ${event.total} bytes`);
} else {
alert(`Received ${event.loaded} bytes`); // 没有 Content-Length
}
};
xhr.onerror = function() {
alert("Request failed");
};
属性
xhr.status HTTP 状态码(一个数字):200,404,403 等,如果出现非 HTTP 错误,则为 0。
xhr.statusText HTTP 状态消息(一个字符串):状态码为 200 对应于 OK,404 对应于 Not Found,403 对应于 Forbidden。
xhr.response(旧脚本可能用的是 responseText)服务器的 response body。
xhr.timeout 超时时间,当在给定timeout时间中未请求成功将触发timeout事件。
xhr.readyState XMLHttpRequest 的状态(state)会随着它的处理进度变化而变化。可以通过 xhr.readyState 来了解当前状态。
XMLHttpRequest 对象以 0 → 1 → 2 → 3 → … → 3 → 4 的顺序在它们之间转变。每当通过网络接收到一个数据包,就会重复一次状态 3。
UNSENT = 0; // 初始状态
OPENED = 1; // open 被调用
HEADERS_RECEIVED = 2; // 接收到 response header
LOADING = 3; // 响应正在被加载(接收到一个数据包)
DONE = 4; // 请求完成
可以使用onreadystatechange来监听,现在被onload等替代
xhr.onreadystatechange = function() {
if (xhr.readyState == 3) {
// 加载中
}
if (xhr.readyState == 4) {
// 请求完成
}
};
方法
xhr.open(method, URL, [async, user, password])
method —— HTTP 方法。通常是 "GET" 或 "POST"。
URL —— 要请求的 URL,通常是一个字符串,也可以是 URL 对象。
async —— 默认为true,如果显式地设置为 false,那么请求将会以同步的方式处理。同步处理xhr请求可能导致页面卡死,具体样子类似在代码段中间使用alert函数。
user,password —— HTTP 基本身份验证(如果需要的话)的登录名和密码。
xhr.send([body]) 该参数用于post传递request body
xhr.abort() 中断请求,触发abort事件,xhr.status变为0
http-header:
**setRequestHeader(name, value) ** 设置头部
getResponseHeader(name) 获取具有给定 name 的 header(Set-Cookie 和 Set-Cookie2 除外)。
getAllResponseHeaders() 返回除 Set-Cookie 和 Set-Cookie2 外的所有 response header。
POST: 使用js内建对象FormData或者使用json,来构造post的request body
<form name="person">
<input name="name" value="John">
<input name="surname" value="Smith">
</form>
<script>
// 从表单预填充 FormData
let formData = new FormData(document.forms.person);
// 附加一个字段
formData.append("middle", "Lee");
// 将其发送出去
let xhr = new XMLHttpRequest();
xhr.open("POST", "/article/xmlhttprequest/post/user");
xhr.send(formData);
xhr.onload = () => alert(xhr.response);
</script>
/**********************************************/
let xhr = new XMLHttpRequest();
let json = JSON.stringify({
name: "John",
surname: "Smith"
});
xhr.open("POST", '/submit')
xhr.setRequestHeader('Content-type', 'application/json; charset=utf-8');
xhr.send(json);
事件
按生命周期排序:
- loadstart —— 请求开始。
- progress —— 一个响应数据包到达,此时整个 response body 都在 response 中。
- abort —— 调用 xhr.abort() 取消了请求。
- error —— 发生连接错误,例如,域错误。不会发生诸如 404 这类的 HTTP 错误。
- load —— 请求成功完成。
- timeout —— 由于请求超时而取消了该请求(仅发生在设置了 timeout 的情况下)。
- loadend —— 在 load,error,timeout 或 abort 之后触发。
- 旧 readystatechange error,abort,timeout 和 load 事件是互斥的。其中只有一种可能发生。
上传进度 xhr.upload对象
跨域:同源策略
同源:是指 url 的 域名、协议、端口 相同。
同源策略,有以下两种:
- DOM 同源策略:禁止对不同源页面 DOM 进行操作。这里主要场景是 iframe 跨域的情况,不同域名的 iframe 是限制互相访问的。
- XMLHttpRequest 同源策略:禁止使用 XHR 对象向不同源的服务器地址发起 HTTP 请求。
为什么要针对这两种进行防范? 1.
如果没有 DOM 同源策略,也就是说不同域的 iframe 之间可以相互访问,那么黑客可以这样进行攻击:
做一个假网站,里面用 iframe 嵌套一个银行网站 http://mybank.com。
把 iframe 宽高啥的调整到页面全部,这样用户进来除了域名,别的部分和银行的网站没有任何差别。
这时如果用户输入账号密码,我们的主网站可以跨域访问到 http://mybank.com 的 dom 节点,就可以拿到用户的账户密码了。
如果没有 XMLHttpRequest 同源策略,那么黑客可以进行 CSRF(跨站请求伪造) 攻击:
用户登录了自己的银行页面 http://mybank.com,http://mybank.com 向用户的 cookie 中添加用户标识。
用户浏览了恶意页面 http://evil.com,执行了页面中的恶意 AJAX 请求代码。
http://evil.com 向 http://mybank.com 发起 AJAX HTTP 请求,请求会默认把 http://mybank.com 对应 cookie 也同时发送过去。
银行页面从发送的 cookie 中提取用户标识,验证用户无误,response 中返回请求数据。此时数据就泄露了。
而且由于 Ajax 在后台执行,用户无法感知这一过程。
跨域方法
-
cors 跨域资源共享(主要在服务器端进行配置),缺点是兼容性不好
-
跨域方法jsonp(JSON with Padding)
其中jsonp是由前端来进行操作的,jsonp原理:加载图片 css js 可无视同源策略
根据这一原理,可以构造一个img/js的dom,使其src指向外域,从而根据响应进行操作。
-
img.src可以用于统计打点,可使用第三方统计服务(统计多少人访问了本网页),由于这是浏览器至服务器单向的,所以达到请求数据。
-
通过script.src可实现访问外域,并获得返回数据。
<img src="外域url"> 通过发起向第三方统计打点网站的请求,可以记录访问网站的人次
<script src="外域url">
譬如
// 1. 定义一个 回调函数 handleResponse 用来接收返回的数据
function handleResponse(data) {
console.log(data);
};
// 2. 动态创建一个 script 标签,并且告诉后端回调函数名叫 handleResponse
var body = document.getElementsByTagName('body')[0];
var script = document.gerElement('script');
script.src = 'http://www.laixiangran.cn/json?callback=handleResponse';
body.appendChild(script);
// 3. 通过 script.src 请求 `http://www.laixiangran.cn/json?callback=handleResponse`,
// 4. 后端能够识别这样的 URL 格式并处理该请求,然后返回 handleResponse({"name": "laixiangran"}) 给浏览器
// 5. 浏览器在接收到 handleResponse({"name": "laixiangran"}) 之后立即执行 ,也就是执行 handleResponse 方法,获得后端返回的数据,这样就完成一次跨域请求了。