2025-04-14 日报 Day156

2025-04-14 日报 Day156

Yuyang 前端小白🥬

今日的鸡汤

有人说,世界上最美好的事情就是:我已经长大,你还未老,我有能力报答,你仍然健康。当父母不在年轻,他们最需要的是陪伴。记得常回家看看,忙碌的日程里也要给家留好位置,记得多陪父母聊聊天,简短的日子也能温暖他们许多日子。来日并不方长,请紧紧握住他们变老的手,余生陪他们慢慢走。

今日学习内容

1、JS 红皮书 P711-717 第二十四章:网络请求与远程资源

今日笔记

1、把 Ajax 推到历史舞台上的关键技术是 XMLHttpRequest(XHR)对象。Fetch API 支持期约(promise)和服务线程(service worker),已经成为极其强大的 Web 开发工具。
2、XMLHttpRequest 对象: XMLHttpRequest 对象是浏览器提供的一个 API,用于在后台与服务器交换数据。所有现代浏览器都通过 XMLHttpRequest 构造函数原生支持 XHR 对象:
let xhr = new XMLHttpRequest();

  • 使用XHR: 使用XHR对象首先先要调用 open()方法,这个方法接收 3 个参数:请求类型(”get”、”post”等)、请求 URL,以及表示请求是否异步的布尔值。下面是一个例子:
    xhr.open(“get”, “example.php”, false);
    这行代码就可以向 example.php 发送一个同步的 GET 请求。关于这行代码需要说明几点。首先,这里的 URL 是相对于代码所在页面的,当然也可以使用绝对 URL。其次,调用 open()不会实际发送请求,只是为发送请求做好准备。
    注意 只能访问同源 URL,也就是域名相同、端口相同、协议相同。如果请求的 URL 与发送请求的页面在任何方面有所不同,则会抛出安全错误。
    要发送定义好的请求,必须像下面这样调用 send()方法:
    xhr.open(“get”, “example.txt”, false);
    xhr.send(null);
    send()方法接收一个参数,是作为请求体发送的数据。如果不需要发送请求体,则必须传 null,因为这个参数在某些浏览器中是必需的。调用 send()之后,请求就会发送到服务器。
    因为这个请求是同步的,所以 JavaScript 代码会等待服务器响应之后再继续执行。收到响应后,XHR对象的以下属性会被填充上数据。
     responseText:作为响应体返回的文本。
     responseXML:如果响应的内容类型是”text/xml”或”application/xml”,那就是包含响应数据的 XML DOM 文档。
     status:响应的 HTTP 状态。
     statusText:响应的 HTTP 状态描述。
    收到响应后,第一步要检查 status 属性以确保响应成功返回。一般来说,HTTP 状态码为 2xx 表示成功。此时,responseText 或 responseXML(如果内容类型正确)属性中会有内容。如果 HTTP状态码是 304,则表示资源未修改过,是从浏览器缓存中直接拿取的。当然这也意味着响应有效。为确保收到正确的响应,应该检查这些状态,如下所示:
    xhr.open(“get”, “example.txt”, false);
    xhr.send(null);
    if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
    alert(xhr.responseText);
    } else {
    alert(“Request was unsuccessful: “ + xhr.status);
    }
    虽然可以像前面的例子一样发送同步请求,但多数情况下最好使用异步请求,这样可以不阻塞JavaScript 代码继续执行。XHR 对象有一个 readyState 属性,表示当前处在请求/响应过程的哪个阶段。这个属性有如下可能的值。
     0:未初始化(Uninitialized)。尚未调用 open()方法。
     1:已打开(Open)。已调用 open()方法,尚未调用 send()方法。
     2:已发送(Sent)。已调用 send()方法,尚未收到响应。
     3:接收中(Receiving)。已经收到部分响应。
     4:完成(Complete)。已经收到所有响应,可以使用了。
    每次 readyState 从一个值变成另一个值,都会触发 readystatechange 事件。可以借此机会检查 readyState 的值。一般来说,我们唯一关心的 readyState 值是 4,表示数据已就绪。为保证跨浏览器兼容,onreadystatechange 事件处理程序应该在调用 open()之前赋值。来看下面的例子:
    let xhr = new XMLHttpRequest();
    xhr.onreadystatechange = function() {
    if (xhr.readyState == 4) {
    if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
    alert(xhr.responseText);
    } else {
    alert(“Request was unsuccessful: “ + xhr.status);
    }
    }
    };
    xhr.open(“get”, “example.txt”, true);
    xhr.send(null);
    在收到响应之前如果想取消异步请求,可以调用 abort()方法:
    xhr.abort();
    调用这个方法后,XHR 对象会停止触发事件,并阻止访问这个对象上任何与响应相关的属性。中断请求后,应该取消对 XHR 对象的引用。由于内存问题,不推荐重用 XHR 对象
  • HTTP头部: 每个 HTTP 请求和响应都会携带一些头部字段,这些字段可能对开发者有用。XHR 对象会通过一些方法暴露与请求和响应相关的头部字段。默认情况下,XHR 请求会发送以下头部字段。
     Accept:浏览器可以处理的内容类型。
     Accept-Charset:浏览器可以显示的字符集。
     Accept-Encoding:浏览器可以处理的压缩编码类型。
     Accept-Language:浏览器使用的语言。
     Connection:浏览器与服务器的连接类型。
     Cookie:页面中设置的 Cookie。
     Host:发送请求的页面所在的域。
     Referer:发送请求的页面的 URI。注意,这个字段在 HTTP 规范中就拼错了,所以考虑到兼容性也必须将错就错。(正确的拼写应该是 Referrer。)
     User-Agent:浏览器的用户代理字符串。
    虽然不同浏览器发送的确切头部字段可能各不相同,但这些通常都是会发送的。如果需要发送额外的请求头部,可以使用 setRequestHeader()方法。这个方法接收两个参数:头部字段的名称和值。为保证请求头部被发送,必须在 open()之后、send()之前调用 setRequestHeader(),如下面的例
    子所示:
    let xhr = new XMLHttpRequest();
    xhr.onreadystatechange = function() {
    if (xhr.readyState == 4) {
    if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
    alert(xhr.responseText);
    } else {
    alert(“Request was unsuccessful: “ + xhr.status);
    }
    }
    };
    xhr.open(“get”, “example.php”, true);
    xhr.setRequestHeader(“MyHeader”, “MyValue”);
    xhr.send(null);
  • GET请求: 最常用的请求方法是 GET 请求,用于向服务器查询某些信息。必要时,需要在 GET 请求的 URL后面添加查询字符串参数。对 XHR 而言,查询字符串必须正确编码后添加到 URL 后面,然后再传给open()方法。
    发送 GET 请求最常见的一个错误是查询字符串格式不对。查询字符串中的每个名和值都必须使用encodeURIComponent()编码,所有名/值对必须以和号(&)分隔,如下面的例子所示:
    xhr.open(“get”, “example.php?name1=value1&name2=value2”, true);
    可以使用以下函数将查询字符串参数添加到现有的 URL 末尾:
    function addURLParam(url, name, value) {
    url += (url.indexOf(“?”) == -1 ? “?” : “&”);
    url += encodeURIComponent(name) + “=” + encodeURIComponent(value);
    return url;
    }
  • POST请求: 第二个最常用的请求是 POST 请求,用于向服务器发送应该保存的数据。每个 POST 请求都应该在请求体中携带提交的数据,而 GET 请求则不然。POST 请求的请求体可以包含非常多的数据,而且数据可以是任意格式。要初始化 POST 请求,open()方法的第一个参数要传”post”,比如:
    xhr.open(“post”, “example.php”, true);
    默认情况下,对服务器而言,POST 请求与提交表单是不一样的。服务器逻辑需要读取原始 POST数据才能取得浏览器发送的数据。不过,可以使用 XHR 模拟表单提交。为此,第一步需要把 ContentType 头部设置为”application/x-www-formurlencoded”,这是提交表单时使用的内容类型。第二步是创建对应格式的字符串。POST 数据此时使用与查询字符串相同的格式。如果网页中确实有一个表单需要序列化并通过 XHR 发送到服务器,则可以使用第 14 章的 serialize()函数来创建相应的字符串,如下所示:
    function submitData() {
    let xhr = new XMLHttpRequest();
    xhr.onreadystatechange = function() {
    if (xhr.readyState == 4) {
    if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
    alert(xhr.responseText);
    } else {
    alert(“Request was unsuccessful: “ + xhr.status);
    }
    }
    };
    xhr.open(“post”, “postexample.php”, true);
    xhr.setRequestHeader(“Content-Type”, “application/x-www-form-urlencoded”);
    let form = document.getElementById(“user-info”);
    xhr.send(serialize(form));
    }
    注意 POST 请求相比 GET 请求要占用更多资源。从性能方面说,发送相同数量的数据,GET 请求比 POST 请求要快两倍。
  • XMLHttpRequest Level2: 现代 Web 应用程序中经常需要对表单数据进行序列化,因此 XMLHttpRequest Level 2 新增了FormData 类型。FormData 类型便于表单序列化,也便于创建与表单类似格式的数据然后通过 XHR发送。下面的代码创建了一个 FormData 对象,并填充了一些数据:
    let data = new FormData();
    data.append(“name”, “Nicholas”);
    append()方法接收两个参数:键和值,相当于表单字段名称和该字段的值。可以像这样添加任意多个键/值对数据。此外,通过直接给 FormData 构造函数传入一个表单元素,也可以将表单中的数据作为键/值对填充进去:
    let data = new FormData(document.forms[0]);
    有了 FormData 实例,可以像下面这样直接传给 XHR 对象的 send()方法:
    let xhr = new XMLHttpRequest();
    xhr.onreadystatechange = function() {
    if (xhr.readyState == 4) {
    if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
    alert(xhr.responseText);
    } else {
    alert(“Request was unsuccessful: “ + xhr.status);
    }
    }
    };
    xhr.open(“post”, “postexample.php”, true);
    let form = document.getElementById(“user-info”);
    xhr.send(new FormData(form));
    使用 FormData 的另一个方便之处是不再需要给 XHR 对象显式设置任何请求头部了。XHR 对象能够识别作为 FormData 实例传入的数据类型并自动配置相应的头部。
    IE8 给 XHR 对象增加了一个 timeout 属性,用于表示发送请求后等待多少毫秒,如果响应不成功就中断请求。之后所有浏览器都在自己的 XHR 实现中增加了这个属性。在给 timeout 属性设置了一个时间且在该时间过后没有收到响应时,XHR 对象就会触发 timeout 事件,调用 ontimeout 事件处理程序。这个特性后来也被添加到了 XMLHttpRequest Level 2 规范。下面看一个例子:
    let xhr = new XMLHttpRequest();
    xhr.onreadystatechange = function() {
    if (xhr.readyState == 4) {
    try {
    if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
    alert(xhr.responseText);
    } else {
    alert(“Request was unsuccessful: “ + xhr.status);
    }
    } catch (ex) {
    // 假设由 ontimeout 处理
    }
    }
    };
    xhr.open(“get”, “timeout.php”, true);
    xhr.timeout = 1000; // 设置 1 秒超时
    xhr.ontimeout = function() {
    alert(“Request did not return in a second.”);
    };
    xhr.send(null);
    Firefox 首先引入了 overrideMimeType()方法用于重写 XHR 响应的 MIME 类型。这个特性后来也被添加到了 XMLHttpRequest Level 2。因为响应返回的 MIME 类型决定了 XHR 对象如何处理响应,所以如果有办法覆盖服务器返回的类型,那么是有帮助的
    假设服务器实际发送了 XML 数据,但响应头设置的 MIME 类型是 text/plain。结果就会导致虽然数据是 XML,但 responseXML 属性值是 null。此时调用 overrideMimeType()可以保证将响应当成 XML 而不是纯文本来处理:
    let xhr = new XMLHttpRequest();
    xhr.open(“get”, “text.php”, true);
    xhr.overrideMimeType(“text/xml”);
    xhr.send(null);
此页目录
2025-04-14 日报 Day156