在最早,JS 并不能直接发送网络请求,我们要发送网络请求只能通过 form 表单的提交按钮来做,后来发送网络请求的接口暴露给了 JS,JS 也就拥有了发送网络请求的能力,JS 用于发送网络请求的这一套接口其实就是 AJAX。
网络通信是一个典型的异步场景,这也算是一个常识,我们不可能在等待网络请求的过程中让浏览器卡死
最开始,IE 提供了一套 AJAX 接口,称为 XMLHttpRequest,简称 XHR,其通过回调的模式来解决这个网络的异步场景,但是这套 API 确实非常反人类,也存在很多缺陷,所以在 ES 6 发布以后,提供了 fetch 函数来优化 AJAX 请求。
不管是 fetch 还是 XHR,都是 AJAX 技术的一种实现,只不过 fetch 比 XHR 更加完善,所以我们的重点也应该在 fetch 上。
XHR
js
var xhr = new XMLHttpRequest(); //创建发送请求的对象
xhr.onreadystatechange = function () {
//当请求状态发生改变时运行的函数
// xhr.readyState: 一个数字,用于判断请求到了哪个阶段
// 0: 刚刚创建好了请求对象,但还未配置请求(未调用open方法)
// 1: open方法已被调用
// 2: send方法已被调用
// 3: 正在接收服务器的响应消息体
// 4: 服务器响应的所有内容均已接收完毕
// xhr.responseText: 获取服务器响应的消息体文本
// xhr.getResponseHeader("Content-Type") 获取响应头Content-Type
};
xhr.open('请求方法', 'url地址'); //配置请求
xhr.setRequestHeader('Content-Type', 'application/json'); //设置请求头
xhr.send('请求体内容'); //构建请求体,发送到服务器,如果没有请求体,传递null以上代码和注释就是 XHR 的具体应用,我们的焦点并不在这,所以不展开太多
fetch
使用 fetchAPI 发送请求非常简单,fetchAPI 使用 Promise 解决异步场景,这给我们提供了非常多的方便。
js
fetch("https://www.baidu.com");这样就对 https://www.baidu.com 发送了一个 GET 请求,这个 fetch 方法返回的是一个 Promise,这个 Promise 将会在收到响应头后完成,完成后的对象为一个响应对象,所以我们可以有以下的代码:
js
fetch("https://www.baidu.com").then(resp => {
console.log(resp);//此时拿到了响应对象
});注意,这个代码肯定会报跨域错误,后面会介绍这个问题,这里只说理论上
这个响应对象上面有很多属性和方法,比如 url 属性可以拿到请求的 URL 地址,比如 status 可以拿到相应的状态码,statusText 可以拿到状态消息,这个 Response 对象可以参考:Response - Web API | MDN
此时其实在这个响应对象里我们已经拿到了响应头的信息,可以通过 header 属性访问到响应头,该对象为一个 Header 对象,可以参考 Headers - Web API | MDN
当然,我们更关心的其实是如何获取响应体,响应对象中有一组函数可以用于获取响应体
arrayBuffer():以 arrayBuffer 的形式获取响应体bolb():以 blob 的形式获取响应体formData():以 formData 的形式获取响应体json():以 json 的形式获取响应体text():以纯文本的形式获取响应体
这些函数返回的依然是 Promise,毕竟读取响应体本身也是网络操作,所以也得是异步的,所以我们就可以写出如下代码:
js
fetch("https://www.baidu.com").then(resp => {
return resp.json();
}).then(data => {
console.log(data);//此时就以JSON的格式获取到了响应体
});我们主要使用
text和json这两个函数。
我们发现,我们这里使用 fetch 发送的都是 GET 请求,我们如何来指定请求类型呢?如何设置请求头和请求体呢?这就涉及到 fetch 的第二个参数,fetch 的第二个参数为一个配置对象,配置对象中有以下配置:
- headers:此配置为一个对象,这个对象的键值对会被添加到请求头中去
- method:此配置为一个字符串,可以用于指定请求类型
- body:此配置为一个字符串,用于配置请求体
以上三个仅仅是常用的配置,我们用这三个已经足够了,详细配置可以参考:全局函数 fetch() - Web API | MDN
常见问题
在使用 AJAX 获取数据的时候,经常会遇到下面的问题,这里作出总结
跨域错误

这个错误通常发生在 AJAX 请求的时候,是一个跨域错误,这里需要了解什么叫跨域。
浏览器为了安全,制定了一个规则,即页面的源和请求目标的源应该保持一致,如果不一致,就产生了跨源或者叫跨域。
源 = 协议 + 主机 + 端口
比如:
| 页面源 | 目标源 | 是否跨域 |
|---|---|---|
| https://baidu.com/news.html | http://103.231.13.42/1.jpg | 是 |
| https://www.baidu.com/news.html | http://baidu.com:8080/1.jpg | 是 |
| https://baidu.com/news.html | https://baidu.com/1.jpg | 否 |
浏览器对 img、link、script 的限制比较宽松,一般允许跨域
浏览器对 AJAX 比较严格,一般不允许跨域
浏览器对跨域行为作出的不同限制,统称为同源策略
如果在 AJAX 中出现跨域请求,就会报出以上错误。
但如果服务器明确告知浏览器允许跨域,则浏览器会允许 AJAX 跨域请求,所以实际上这个问题是后端需要解决的,我们是不需要解决的。
404 错误

浏览器请求某个资源,但服务器响应了一个 404 状态码,就会在控制台中报出这个错误。与此同时,你可以在浏览器的网络调试中进一步观察到这个错误。
404 错误是一种非常常见的错误,它表示服务器告诉客户端:你要的资源并不存在
要解决这个错误,首先要检查请求的 url 地址是否正确。如果 url 地址正确,则可能是服务器的问题,需要联系后端开发人员或者将问题上报
favicon

报错内容:加载资源失败:服务器响应了 404 状态码
请求地址::5500/favicon.ico
原因:
很多浏览器在解析页面后,如果发现页面中并没有使用link元素加载站点图标,会尝试请求以下地址来获取图标:
站点协议://站点主机:站点端口/favicon.ico
如果这个地址无法获得图标,就会报出相应错误
该错误会在下一次刷新后消失,是因为再次刷新后,浏览器_记忆_了之前无法获取图标的情况,就不再发出请求了。
其他问题
网络断开,检查你的网络连接,或者检查你是否在调试工具中进行了网络断开调试
访问的域名不存在,无法连接到服务器

