发送 AJAX 请求
- 第一步:创建一个 XHR 对象:不兼容 XMLHttpRequest 的浏览器 (IE6) 使用 ActiveXObject 创建;
- 第二步:打开请求连接(配置请求信息):
// method 请求方式 // url 请求地址 // async 是否为异步请求,默认是 true 异步 // user-name, user-pass 向服务器发送请求所携带的用户名密码(一般不用) xhr.open(method, url, async, user-name, user-pass);
- 第三步:监听请求状态,在不同状态中做不同的事情;
- 第四步:发送 AJAX 请求;
XHR 的属性
属性 | 描述 |
---|---|
xhr.response | 响应体数据,类型取决于 responseType 的指定 |
xhr.status | 响应状态码值,比如 200、404 ----标识着请求成功或者失败 |
xhr.statusText | 响应状态文本 |
xhr.timeout | 指定请求超时时间,默认为 0 代表没有限制 |
xhr.withCredentials | 值为 true:跨域资源共享中,允许携带资源凭证 |
xhr.readyState | 表示请求状态: 0 创建完 XHR 1 已经完成 OPEN 操作 2 服务器已经把响应头信息返回了 3 响应主体正在返回中 4 响应主体已经返回 |
XHR 的方法
方法 | 描述 |
---|---|
xhr.abort() | 强制中断请求 |
xhr.getAllResponseHeaders() | 获取所有请求头 |
xhr.getResponseHeader() | 获取请求头 |
xhr.setRequestHeader() | 设置请求头(属性值不能是中文和特殊字符) |
xhr.open(method,url[,async]) | 初始化一个请求 |
xhr.overrideMimeType() | 重写资源类型 |
xhr.send() | 发送请求 |
XHR 的事件
方法 | 描述 |
---|---|
load | 在接收到完整的响应数据时触发 |
readystatechange | 每当 readyState 属性改变时,就会调用该函数 |
error | 在请求发生错误时触发 |
HTTP 请求
请求 | 描述 |
---|---|
GET | 客户端都可以把信息传递给服务器,服务器也可以把信息返回给客户端,只不过 GET 偏向于拿 |
DELETE | 删除,一般代指删除服务器上指定的文件 |
HEAD | 只获取响应头的信息,不获取响应主体内容 |
OPTIONS | 试探性请求,在 CORS 跨域请求中,所以正常请求发送前,先发送一个试探请求,验证是否可以和服务器正常的建立连接 |
POST | 客户端都可以把信息传递给服务器,服务器也可以把信息返回给客户端,POST 偏向于给 |
PUT | 新增,一般代指向服务器中新增文件 |
HTTP 状态码 xhr.status
2 开头的状态码(成功类)
3 开头的状态码(重定向)
4 开头的状态码(客户端错误)
5 开头的状态码(服务器错误)
状态码 | 描述 |
---|---|
200 | 服务器已成功处理了请求 |
202 | 服务器已接受请求,但尚未处理 |
301 | 永久性重定向,表示资源已被分配了新的 URL |
302 | 临时性重定向,表示资源临时被分配了新的 URL |
303 | 表示资源存在另一个 URL ,用 GET 方法获取资源 |
304 | 自从上次请求后,请求网页未修改过,服务器返回此响应时,不会返回网页内容 |
400 | 服务器不理解请求的语法 |
401 | 表示发送的请求需要有通过 HTTP 认证的认证信息 |
403 | 服务器拒绝请求 |
404 | 服务器找不到请求网页 |
500 | 服务器遇到错误,无法完成请求 |
503 | 表示服务器处于停机维护或超负载,无法处理请求 |
Content-Type 详解
Content-Type 即是 Internet Media Type 互联网媒体类型,也叫做 MIME 类型,在互联网中有成百上千中不同的数据类型,HTTP 在传输数据对象时会为他们打上称为 MIME 的数据格式标签,用于区分数据类型;
在 HTTP 协议消息头中,使用 Content-Type 来表示请求和响应中的媒体类型信息,来告诉服务端如何处理请求的数据,以及告诉客户端(一般是浏览器)如何解析响应的数据,比如显示图片,解析并展示 html 等等;
Content-Type 格式
Content-Type 的格式:Content-Type:type/subtype;parameter
- type:主类型,任意的字符串,如 text 如果是 * 号代表所有;
- subtype:子类型,任意的字符串,如 html 如果是 * 号代表所有,用 / 与主类型隔开;
- parameter:可选参数,如 charset、boundary 等;
常见 Content-Type
Content-Type | 描述 |
---|---|
application/x-www-form-urlencoded | 数据按照 name=zhangsan&age=20 的方式进行编码,非字母或数字的字符会被 进行 URL 转码 |
multipart/form-data | 它支持文件的传输,并且它的传输数据放在 request-payload 里,并且以 bounday 进行分隔 |
application/json | 消息主体是序列化后的 JSON 字符串 |
面试题
倒计时抢购
-
如何从服务器获取时间,以及存在的问题:
- 可以基于 ajax 向服务器发送请求,服务器返回的响应头中包含了服务器时间(GMT 格林威治时间,new Date([转换的时间] 转换为北京时间 ));
- 由于网络传送存在时差,导致客户端接收到的服务器时间和真实时间存在偏差,当响应头信息返回(AJAX 状态为 2 的时候),获取时间即可,HTTP 传输中的 HEAD 请求方式,就是只获取响应头的信息;
- 获取当前客户端本地的时间 (但是这个时间客户可以修改自己本地的时间):真实项目中只能做一些参考的工作,不能做严谨的校验,严格校验的情况下,需要的时间是从服务器获取的;
-
示例代码:
async function init() { let serverTime = await queryServerTime(), // 获取服务器时间 targetTime = new Date('2020/02/25 20:49:30'), // 目标时间 autoTimer = null; // 定时器 // 计算时间差 function computed() { let spanTime = targetTime - serverTime; if (spanTime <= 0) { // 已经到抢购时间了 spanBox.innerHTML = `00:00:00`; clearInterval(autoTimer); return; } let hours = Math.floor(spanTime / (60 * 60 * 1000)); spanTime = spanTime - hours * 60 * 60 * 1000; let minutes = Math.floor(spanTime / (60 * 1000)); spanTime = spanTime - minutes * 60 * 1000; let seconds = Math.floor(spanTime / 1000); hours = hours < 10 ? '0' + hours : hours; minutes = minutes < 10 ? '0' + minutes : minutes; seconds = seconds < 10 ? '0' + seconds : seconds; spanBox.innerHTML = `${hours}:${minutes}:${seconds}`; } computed(); // 间隔 1S 后重新计算一次 autoTimer = setInterval(async _ => { // 应该重新从服务器获取时间(但是这样有很大延迟和服务器的压力太大了) // serverTime = await queryServerTime(); // 可以基于第一次获取的时间,在原来的基础上,让其自动累加 1000MS 即可 serverTime = new Date(serverTime.getTime() + 1000); computed(); }, 1000); } init();
readyState 变化几次
-
示例代码
JavaScriptJavaScriptJavaScript// 示例 1 let xhr = new XMLHttpRequest; xhr.open('get', './js/fastclick.js', true); // open 执行完:readyState 为 1 // 异步:在 SEND 后,会把这个请求的任务放在 EventQueue 中(宏任务) xhr.send(); // 同步代码,绑定之前 readyState 为 1 xhr.onreadystatechange = function () { console.log(xhr.readyState); //=>2.3.4 };
// 示例 2 let xhr = new XMLHttpRequest; xhr.open('get', './js/fastclick.js', false); // open 执行完:readyState 为 1 xhr.send(); // 同步代码 send 执行完,readyState 为 4 xhr.onreadystatechange = function () { // readyState 绑定之后是 4,一直没有变化,不触发事件 console.log(xhr.readyState); };
// 示例 3 let xhr = new XMLHttpRequest; xhr.open('get', './js/fastclick.js', false); // open 执行完:readyState 为 1 // 同步:此时绑定 readyState 为 1 xhr.onreadystatechange = function () { // 绑定时 readyState 为 1,send 执行完 readyState 为 4,readyState 有变化 触发事件 console.log(xhr.readyState); //=>4 }; // 同步 send 执行完,readyState 为 4 xhr.send();
第 4️⃣ 座大山:同步异步编程、EventLoop
上一篇