如何发请求
我们知道有一些标签可以发送请求:
<form>
表单可以发请求,但是会刷新页面或新开页面。<a>
标签可以发 GET 请求,但是也会刷新页面或新开页面。<img>
标签可以发 GET 请求,但是只能以图片的形式展示。<link>
标签可以发 GET 请求,但是只能以 CSS、favicon 的形式展示。<script>
可以发 GET 请求,但是只能以脚本的形式运行。
但我们想要一种方式可以实现以下功能:
可以发送 GET、POST、PUT、DELETE 等不同类型的请求。
想以什么形式展示就以什么形式展示。
微软的突破
微软在 IE5 率先在 JavaScript 中引入 ActiveX 对象(API),使得 JavaScript 可以直接发起 HTTP 请求。随后,其他浏览器也跟进创造了一个类似的对象,取名为 XMLHttpRequest,并被纳入了 W3C 规范。
什么是 AJAX
Jesse James Garrett 将如下技术取名为 AJAX(Asynchronous JavaScript and XML,异步 JavaScript 和 XML):
使用 XMLHttpRequest 对象发送请求;
服务器返回 XML 格式的字符串;
JavaScript 解析 XML,并更新局部页面。
用原生 JavaScript 发送 AJAX 请求
首先通过
new
操作符和XMLHttpRequest()
构造器创建一个实例对象;创建好实例对象后,就可以通过此对象的
open()
方法发送 HTTP 请求;这个方法接收五个参数,一般要了解的是前三个:第一个参数是字符串,代表请求类型,例如 GET 或 POST 等;
第二个参数也是字符串,表示请求的 URL 地址或路径;
第三个不常用但是比较重要,参数类型是布尔值,
true
表示异步传输,false
表示同步传输。
然后给这个对象绑定监听
onreadystatechange
事件,这个事件称为“通信状态改变事件”,它监听的其实是readyState
属性的变化,这个属性用五个数字代表五种状态:0:UNSENT,代理被创建,但尚未调用
open()
方法。1:OPENED,
open()
方法已经被调用。2:HEADERS_RECEIVED,
send()
方法已经被调用,并且头部和状态已经可获得。3:LOADING,下载中,
responseText
属性已经包含部分数据。4:DONE,下载操作已完成。
从前面的列表中可以看出,只要判断
readyState
属性值为 4 时,就说明请求通信成功。
请求成功后,还要判断返回的状态码,也就是
status
的属性值,如果状态码是 200 证明响应成功了。响应成功后,便可以得到响应返回的数据,这些数据就是
responseText
的属性值,拿到这个值就可以做相应的数据处理。用 AJAX 发送请求就像打手机,先解锁手机(创建对象),然后输入号码(初始化),再拨通这个号码(发送请求),最后等待接通后通话(等待响应及数据处理)。
一个基础的 AJAX 方法示例代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25function ajax(method, url, async, fnSuccess, fnFail) {
let ajax;
// 创建对象
if (window.XMLHttpRequest) {
ajax = new XMLHttpRequest();
} else {
ajax = new ActiveXObject('Microsoft.XMLHTTP');
}
// 初始化
ajax.open(method, url, async);
// 发送请求
ajax.send();
// 接收请求
ajax.onreadystatechange = () => {
if (ajax.readyState === 4) {
if (ajax.status === 200) {
console.log('成功!');
fnSuccess(ajax.responseText);
} else {
console.log('失败!');
fnFail && fnFail();
}
}
};
}
JSON 与 JavaScript
JSON 是“抄袭” JavaScript 部分语法后发明的另一种语言。
JSON 中的数据类型和 JavaScript 中的数据类型非常相似,但区别是 JSON 中没有 Undefined 和 Function,并且在 JSON 中,字符串必须使用双引号包裹。
JSON 只是一种数据交换格式,它没有原型链,所以无法传输复杂的数据,例如引用数据类型。
HTTP 请求返回的数据都是以字符串的形式返回,只不过这些字符串可以符合不同的格式,比如 XML 或 JSON。
服务器返回的 JSON 格式字符串,可以使用浏览器提供的
window.JSON.parse()
方法将其转换为对应的 JavaScript 数据,例如对象,或数组等等。
同源策略
为什么 form 表单提交没有跨域问题,而 AJAX 提交却有跨域问题呢?
这是因为原页面用 form 表单提交到另一个域名后,会跳转到新页面,原页面的脚本无法获取新页面中的内容,这在浏览器认为是安全的。
而 AJAX 是可以读取响应内容的,并且不会跳转新页面,所以浏览器不允许 AJAX 被响应;用 AJAX 是可以成功地将请求发送出去的,只是接收不到服务器的响应。
前面的问题其实体现的是浏览器的同源策略;同源策略的含义是:A 网页设置的 Cookie,B 网页不能打开,除非两个网页“同源”,同源指的是“三个相同”,即协议相同,域名相同和端口相同。
如果两个网页非同源,那么三种行为会受到限制:
Cookie、LocalStorage 和 IndexDB 无法读取。
DOM 无法获得。
AJAX 请求发送后无法得到响应。
CORS 跨域
如果要突破同源策略,可以使用 CORS 机制来进行跨域。
CORS(Cross-Origin Resource Sharing,跨源资源共享),是一种允许当前域的资源(比如 HTML、JS 等)被其他域的脚本请求访问的机制。
一般要实现 CORS,需要后端为指定共享的 URL 添加一个响应头,例如:response.setHeader('Access-Control-Allow-Origin', url)
;如果允许所有的 URL,可以将参数传入一个通配符字符串 '*'
。