2025-04-15 日报 Day157

2025-04-15 日报 Day157

Yuyang 前端小白🥬

今日的鸡汤

将生活嚼得有滋有味,把日子过得活色生香,往往靠的不只是嘴,还要有一颗浸透人间烟火的心。

今日学习内容

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

今日笔记

1、进度事件: Progress Events 是 W3C 的工作草案,定义了客户端服务器端通信。这些事件最初只针对 XHR,现在也推广到了其他类似的 API。有以下 6 个进度相关的事件。
 loadstart:在接收到响应的第一个字节时触发。
 progress:在接收响应期间反复触发。
 error:在请求出错时触发。
 abort:在调用 abort()终止连接时触发。
 load:在成功接收完响应时触发。
 loadend:在通信完成时,且在 error、abort 或 load 之后触发。
每次请求都会首先触发 loadstart 事件,之后是一个或多个 progress 事件,接着是 error、abort或 load 中的一个,最后以 loadend 事件结束。这些事件大部分都很好理解,但其中有两个需要说明一下。

  • load事件: 最终,增加了一个 load 事件用于替代readystatechange 事件。load 事件在响应接收完成后立即触发,这样就不用检查 readyState 属性了。onload 事件处理程序会收到一个 event 对象,其 target 属性设置为 XHR 实例,在这个实例上可以访问所有 XHR 对象属性和方法。不过,并不是所有浏览器都实现了这个事件的 event 对象。考虑到跨浏览器兼容,还是需要像下面这样使用 XHR 对象变量:
  • progress 事件: Mozilla 在 XHR 对象上另一个创新是 progress 事件,在浏览器接收数据期间,这个事件会反复触发。每次触发时,onprogress 事件处理程序都会收到 event 对象,其 target 属性是 XHR 对象,且包含 3 个额外属性:lengthComputable、position 和 totalSize。其中,lengthComputable 是一个布尔值,表示进度信息是否可用;position 是接收到的字节数;totalSize 是响应的 ContentLength 头部定义的总字节数。有了这些信息,就可以给用户提供进度条了。以下代码演示了如何向用户展示进度:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    let xhr = new XMLHttpRequest(); 
    xhr.onload = function(event) {
    if ((xhr.status >= 200 && xhr.status < 300) ||
    xhr.status == 304) {
    alert(xhr.responseText);
    } else {
    alert("Request was unsuccessful: " + xhr.status);
    }
    };
    xhr.onprogress = function(event) {
    let divStatus = document.getElementById("status");
    if (event.lengthComputable) {
    divStatus.innerHTML = "Received " + event.position + " of " +
    event.totalSize +
    " bytes";
    }
    };
    xhr.open("get", "altevents.php", true);
    xhr.send(null);
    为了保证正确执行,必须在调用 open()之前添加 onprogress 事件处理程序。在前面的例子中,每次触发 progress 事件都会更新 HTML 元素中的信息。假设响应有 Content-Length 头部,就可以利用这些信息计算出已经收到响应的百分比。
    2、跨源资源共享: 通过 XHR 进行 Ajax 通信的一个主要限制是跨源安全策略。默认情况下,XHR 只能访问与发起请求的页面在同一个域内的资源。这个安全限制可以防止某些恶意行为。不过,浏览器也需要支持合法跨源访问的能力。
    跨源资源共享(CORS,Cross-Origin Resource Sharing)定义了浏览器与服务器如何实现跨源通信。CORS 背后的基本思路就是使用自定义的 HTTP 头部允许浏览器和服务器相互了解,以确实请求或响应应该成功还是失败。
    对于简单的请求,比如 GET 或 POST 请求,没有自定义头部,而且请求体是 text/plain 类型,这样的请求在发送时会有一个额外的头部叫 Origin。Origin 头部包含发送请求的页面的源(协议、域名和端口),以便服务器确定是否为其提供响应。下面是 Origin 头部的一个示例:
    Origin: http://www.nczonline.net
    如果服务器决定响应请求,那么应该发送 Access-Control-Allow-Origin 头部,包含相同的源;
    或者如果资源是公开的,那么就包含”*”。比如:
    Access-Control-Allow-Origin: http://www.nczonline.net
    如果没有这个头部,或者有但源不匹配,则表明不会响应浏览器请求。否则,服务器就会处理这个请求。注意,无论请求还是响应都不会包含 cookie 信息。
    现代浏览器通过 XMLHttpRequest 对象原生支持 CORS。在尝试访问不同源的资源时,这个行为会被自动触发。要向不同域的源发送请求,可以使用标准 XHR对象并给 open()方法传入一个绝对 URL,比如:
    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”, “http://www.somewhere-else.com/page/ “, true);
    xhr.send(null);
    跨域 XHR 对象允许访问 status 和 statusText 属性,也允许同步请求。出于安全考虑,跨域 XHR对象也施加了一些额外限制。
     不能使用 setRequestHeader()设置自定义头部。
     不能发送和接收 cookie。
     getAllResponseHeaders()方法始终返回空字符串。
    因为无论同域还是跨域请求都使用同一个接口,所以最好在访问本地资源时使用相对 URL,在访问远程资源时使用绝对 URL。这样可以更明确地区分使用场景,同时避免出现访问本地资源时出现头部或cookie 信息访问受限的问题。
  • 预检请求: CORS 通过一种叫预检请求(preflighted request)的服务器验证机制,允许使用自定义头部、除 GET和 POST 之外的方法,以及不同请求体内容类型。在要发送涉及上述某种高级选项的请求时,会先向服务器发送一个“预检”请求。这个请求使用 OPTIONS 方法发送并包含以下头部。
     Origin:与简单请求相同。
     Access-Control-Request-Method:请求希望使用的方法。
     Access-Control-Request-Headers:(可选)要使用的逗号分隔的自定义头部列表。
    下面是一个假设的 POST 请求,包含自定义的 NCZ 头部:
    Origin: http://www.nczonline.net
    Access-Control-Request-Method: POST
    Access-Control-Request-Headers: NCZ
    在这个请求发送后,服务器可以确定是否允许这种类型的请求。服务器会通过在响应中发送如下头部与浏览器沟通这些信息。
     Access-Control-Allow-Origin:与简单请求相同。
     Access-Control-Allow-Methods:允许的方法(逗号分隔的列表)。
     Access-Control-Allow-Headers:服务器允许的头部(逗号分隔的列表)。
     Access-Control-Max-Age:缓存预检请求的秒数。
    例如:
    Access-Control-Allow-Origin: http://www.nczonline.net
    Access-Control-Allow-Methods: POST, GET
    Access-Control-Allow-Headers: NCZ
    Access-Control-Max-Age: 1728000
    预检请求返回后,结果会按响应指定的时间缓存一段时间。换句话说,只有第一次发送这种类型的请求时才会多发送一次额外的 HTTP 请求。
  • 凭据请求: 默认情况下,跨源请求不提供凭据(cookie、HTTP 认证和客户端 SSL 证书)。可以通过将withCredentials 属性设置为 true 来表明请求会发送凭据。如果服务器允许带凭据的请求,那么可以在响应中包含如下 HTTP 头部:
    Access-Control-Allow-Credentials: true
    如果发送了凭据请求而服务器返回的响应中没有这个头部,则浏览器不会把响应交给 JavaScript(responseText 是空字符串,status 是 0,onerror()被调用)。注意,服务器也可以在预检请求的响应中发送这个 HTTP 头部,以表明这个源允许发送凭据请求。
    3、替代性跨域技术: CORS 出现之前,实现跨源 Ajax 通信是有点麻烦的。开发者需要依赖能够执行跨源请求的 DOM 特性,在不使用 XHR 对象情况下发送某种类型的请求。虽然 CORS 目前已经得到广泛支持,但这些技术仍然没有过时,因为它们不需要修改服务器。
  • 图片探测: 图片探测是利用标签实现跨域通信的最早的一种技术。任何页面都可以跨域加载图片而不必担心限制,因此这也是在线广告跟踪的主要方式。可以动态创建图片,然后通过它们的 onload 和onerror 事件处理程序得知何时收到响应。
    这种动态创建图片的技术经常用于图片探测(image pings)。图片探测是与服务器之间简单、跨域、单向的通信。数据通过查询字符串发送,响应可以随意设置,不过一般是位图图片或值为 204 的状态码。浏览器通过图片探测拿不到任何数据,但可以通过监听 onload 和 onerror 事件知道什么时候能接收到响应。下面看一个例子:
    let img = new Image();
    img.onload = img.onerror = function() {
    alert(“Done!”);
    };
    img.src = “http://www.example.com/test?name=Nicholas “;
    这个例子创建了一个新的 Image 实例,然后为它的 onload 和 onerror 事件处理程序添加了同一个函数。这样可以确保请求完成时无论什么响应都会收到通知。设置完 src 属性之后请求就开始了,这个例子向服务器发送了一个 name 值。
    图片探测频繁用于跟踪用户在页面上的点击操作或动态显示广告。当然,图片探测的缺点是只能发送 GET 请求和无法获取服务器响应的内容。这也是只能利用图片探测实现浏览器与服务器单向通信的原因。
  • JSONP: JSONP 是“JSON with padding”的简写,是在 Web 服务上流行的一种 JSON 变体。JSONP 看起来跟 JSON 一样,只是会被包在一个函数调用里,比如:
    callback({ “name”: “Nicholas” });
    JSONP 格式包含两个部分:回调和数据。回调是在页面接收到响应之后应该调用的函数,通常回调函数的名称是通过请求来动态指定的。而数据就是作为参数传给回调函数的 JSON 数据。下面是一个典型的 JSONP 请求:
    http://freegeoip.net/json/?callback=handleResponse
    这个 JSONP 请求的 URL 是一个地理位置服务。JSONP 服务通常支持以查询字符串形式指定回调函数的名称。比如这个例子就把回调函数的名字指定为 handleResponse()。
    JSONP 调用是通过动态创建
    访问人数 总访问量
    Hexo 驱动 主题 Redefine v2.6.4