JavaScript高级程序设计(第3版)学习笔记 第21章

本文深入探讨了Ajax和Comet技术,介绍了XHR对象的创建与使用,包括兼容性处理、请求与响应流程、事件监听等。同时,文章还讲解了CORS、JSONP、SSE、WebSockets等高级主题,以及它们在现代Web开发中的应用场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

第21章 Ajax和Comet

1.Ajax 是无需刷新页面就能够从服务器取得数据的一种方法,核心对象是 XMLHttpRequest(XHR)对象。

2.兼容各个浏览器创建XHR对象的方法

function createXHR(){
        if (typeof XMLHttpRequest != "undefined"){
            return new XMLHttpRequest();
        } else if (typeof ActiveXObject != "undefined"){
            //用于兼容IE7之前的版本
           if (typeof arguments.callee.activeXString != "string"){
               var versions = [ "MSXML2.XMLHttp.6.0",  "MSXML2.XMLHttp.3.0","MSXML2.XMLHttp"],
                   i, len;

           for (i=0,len=versions.length; i < len; i++){
               try {
                   new ActiveXObject(versions[i]);
                   arguments.callee.activeXString = versions[i];
                   break;
                } catch (ex){
                    //跳过 
                }
           } 
        }
       return new ActiveXObject(arguments.callee.activeXString);
    } else {
        throw new Error("No XHR object available.");
    }
}

3.使用 XHR 对象时,要调用的第一个方法是 open(),接受 3 个参数:

  • 要发送的请求的类型
  • 请求的 URL 
  • 表示是否异步发送请求的布尔值
xhr.open("get", "example.php", false);

调用 open()方法并不会真正发送请求, 而只是启动一个请求以备发送,只能向同一个域中使用相同端口和协议的 URL 发送请求。

4.使用 XHR 对象时,要调用的第二个方法是send(),接收一个参数,即要作为请求主体发送的数据。
如果不需要通过请求主体发送 数据,则必须传入 null,因为这个参数对有些浏览器来说是必需的。调用 send()之后,请求就会被分派到服务器。

xhr.open("get", "example.txt", false);
xhr.send(null);

5.响应的数据会自动填充 XHR 对象的属性,相关的属性如下:

  • responseText:作为响应主体被返回的文本。
  • responseXML:如果响应的内容类型是"text/xml"或"application/xml",这个属性中将保存包含着响应数据的 XML DOM 文档。
  • status:响应的 HTTP 状态。
  • statusText:HTTP 状态的说明。

6.在接收到响应后:

第一步是检查 status 属性,将 HTTP 状态代码 200 作为成功的标志或者状态代码为 304 表示请求的资源并没有被修改,可以直接使用浏览器中缓存的版本。

(同时多数情况下,我们还是要发送异步请求,才能让 JavaScript 继续执行而不必等待响应。)
此时,可以检测 XHR 对象的 readyState 属性,该属性表示请求 /响应过程的当前活动阶段。这个属性可取的值如下:

0:未初始化。尚未调用open()

1:启动。已经调用open(),但未调用send()

2:发送。已经调用send(),但尚未接收到响应。

3:接收。已经接收到部分响应数据。

4:完成。已经接收到全部响应数据,而且已经可以再客户端使用了。

7.默认情况下,在发送 XHR 请求的同时,还会发送下列头部信息:

  • Accept:浏览器能够处理的内容类型。
  • Accept-Charset:浏览器能够显示的字符集。
  • Accept-Encoding:浏览器能够处理的压缩编码。
  • Accept-Language:浏览器当前设置的语言。
  • Connection:浏览器与服务器之间连接的类型。 
  • Cookie:当前页面设置的任何 Cookie。
  • Host:发出请求的页面所在的域 。
  • Referer:发出请求的页面的 URI。注意,HTTP 规范将这个头部字段拼写错了,而为保证与规范一致,也只能将错就错了。(这个英文单词的正确拼法应该是 referrer。)
  • User-Agent:浏览器的用户代理字符串。

8.setRequestHeader()方法可以设置自定义的请求头部信息,接受两个参数:头部字段的名称和头部字段的值。要成功发送请求头部信息,必须在调用 open()方法之后且调用 send()方法之前调用。

var xhr = createXHR();
xhr.open("get", "example.php", true); 
xhr.setRequestHeader("MyHeader", "MyValue"); 
xhr.send(null);

getResponseHeader()方法并传入头部字段名称,可以取得相应的响应头部信息。

var myHeader = xhr.getResponseHeader("MyHeader");

getAllResponseHeaders()方法则可以取得一个包含所有头部信息的长字符串。

9.GET 是最常见的请求类型,最常用于向服务器查询某些信息。必要时,可以将查询字符串参数追加 到 URL 的末尾,以便将信息发送给服务器。查询字符串中每个参数的名 称和值都必须使用 encodeURIComponent()进行编码,然后才能放到 URL 的末尾;而且所有名-值对 儿都必须由和号(&)分隔。
下面函数可以辅助向现有 URL 的末尾添加查询字符串参数,接受三个参数:要添加参数的 URL、参数的名称和参数的值。

function addURLParam(url, name, value) {
        url += (url.indexOf("?") == -1 ? "?" : "&");
        url += encodeURIComponent(name) + "=" + encodeURIComponent(value);
        return url;
}

10.POST 请求,通常用于向服务器发送应该被保存的数据。发送 POST 请求的第二步就是向 send()方法中传入某些数据。

11.FormData 类型为序列化表单以及创建与表单格式相同的数据(用于通过 XHR 传输)提供了便利。

//创建了一个 FormData 对象,并向其中添加了一些数据,append()方法接收两个参数:键和值,分别对应表单字段的名字和字段中包含的值。
var data = new FormData();
data.append("name", "Nicholas");
//通过向 FormData 构造函数中传入表单元素,也可以用表单元素的数据 预先向其中填入键值对儿
var data = new FormData(document.forms[0]);

12.overrideMimeType()方法,用于重写 XHR 响应的 MIME 类型。调用 overrideMimeType()必须在 send()方法之前,才能保证重写响应的 MIME 类型。

var xhr = createXHR(); 
xhr.open("get", "text.php", true); 
xhr.overrideMimeType("text/xml"); 
xhr.send(null);

13.有 6 个进度事件,每个请求都从触发 loadstart 事件开始,接下来是一或多个 progress 事件,然后触发 error、abort 或 load 事件中的一个,最后以触发 loadend 事件结束:

  • loadstart:在接收到响应数据的第一个字节时触发。
  • progress:在接收响应期间持续不断地触发。
  • error:在请求发生错误时触发。
  • abort:在因为调用 abort()方法而终止连接时触发。
  • load:在接收到完整的响应数据时触发。
  • loadend:在通信完成或者触发 error、abort 或 load 事件后触发。

14.progress 事件会在浏览器接收新数据期间周期性地触发。onprogress 事件处理程序会接收到一个 event 对象,其 target 属性是 XHR 对象,包含着三个额外的属性:lengthComputable、position 和 totalSize。其中,lengthComputable 是一个表示进度信息是否可用的布尔值,position 表示已经接收的字节数,totalSize 表示根据 Content-Length 响应头部确定的预期字节数。为用户创建一个进度指示器:

var xhr = createXHR(); 
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){
    var 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);

15.默认情况下,XHR 对象只能访问与包含它的页面位于同一个域中的资源。CORS(Cross-Origin Resource Sharing,跨源资源共享),定义了在必须访问跨源资源时,浏览器与服务器应该如何沟通。CORS 背后的基本思想,就是使用自定义的 HTTP 头部 让浏览器与服务器进行沟通,从而决定请求或响应是应该成功,还是应该失败。

16.浏览器对 CORS 的支持程度并不都一样,但所有浏览器都支持简单的(非 Preflight 和不带凭据 的)请求,因此有必要实现一个跨浏览器的方案。检测 XHR(Firefox 3.5+、Safari 4+、Chrome、iOS 版 Safari 和 Android 平台中的 WebKit 都通过 XMLHttpRequest 对象实现了对 CORS 的原生支持。) 是否支持 CORS 的最简单方式,就是检查是否存在 withCredentials 属性( 通过将 withCredentials 属性设置为 true,可以指定某个请求应该发送凭据)。再结合检测 XDomainRequest 对象(检测IE)是否存在,就可以兼顾所有浏览器了。

function createCORSRequest(method, url){
    var xhr = new XMLHttpRequest();
    if ("withCredentials" in xhr){
        xhr.open(method, url, true);
    } else if (typeof XDomainRequest != "undefined"){
        xhr = new XDomainRequest();
        xhr.open(method, url);
    } else {
        xhr = null;
    }
    return xhr; 
}

var request = createCORSRequest("get", "http://www.somewhere-else.com/page/"); 
if (request){
    request.onload = function(){
    //对 request.responseText 进行处理
    };
    request.send();
}

17.图像 Ping 最常用于跟踪用户点击页面或动态广告曝光次数,有两个主要的缺点,一是只能发送 GET 请求,二是无法访问服务器的响应文本。因此,图像 Ping 只能用于浏览器与服务器间的单向通信。通过 图像 Ping,浏览器得不到任何具体的数据,通过侦听 load 和 error 事件,能知道响应是什么时候接收到的。

/*创建了一个 Image 的实例,然后将 onload 和 onerror 事件处理程序指定为同一个函数,只要请求完成,就能得到通知。
请求从设置 src 属性那一刻开始。
这个例子在请求中发送了一个 name 参数。*/
var img = new Image();
img.onload = img.onerror = function(){
    alert("Done!");
};
img.src = "http://www.example.com/test?name=Nicholas";

18.JSONP(JSON with padding/填充式 JSON 或参数式 JSON)由两部分组成:回调函数和数据。

  • 回调函数:响应到来时应该在页面中调用的函数,名字一般是在请求中指定的。
  • 数据:传入回调函数中的 JSON 数据。

优点:能够直接访问响应文本,支持在浏览器与服务器之间双向通信。

不足:1⃣️从其他域中加载代码执行。如果其他域不安全,很可能会在响应中夹带一些恶意代码

            2⃣️确定 JSONP 请求是否失败并不容易

JSONP 是通过动态<script>元素来使用的,使用时可以为src 属性指定一个跨域 URL。因为 JSONP 是有效的 JavaScript 代码,所以在请求完成后,即在 JSONP 响应加载到页面中以后,就会立即执行。

//通过查询地理定位服务来显示你的 IP 地址和位置信息。
function handleResponse(response){
    alert("You’re at IP address " + response.ip + ", which is in " +
          response.city + ", " + response.region_name);
}
var script = document.createElement("script");
script.src = "http://freegeoip.net/json/?callback=handleResponse"; document.body.insertBefore(script, document.body.firstChild);

19.Comet :一种服务器向页面推送数据的技术,能够让信息近乎实时地被推送到页面上,非常适合处理体育比赛的分数和股票报价。实现 Comet 的手段 主要有两个:长轮询和 HTTP 流。

  • 长轮询:页面发起一个到服务器的请求,然后服务器一直保持连接打开,直到有数据可发送。发送完数据之后,浏览器关闭连接,随即又发起一个到服务器的新请求。所有浏览器都支持
  • HTTP 流:浏览器向服务器发送一个请求,而服务器保持连接打开,然后周期性地向浏览器发送数据。
  • /*createStreamingClient()函数接收三个参数:要连接的 URL、在接收到数据时调用的函 数以及关闭连接时调用的函数。
    监听readyState 值为 3,就对 responseText 进行分割以取得最新数据。(当 readyState 值变为 3 时,responseText 属性中就会保 存接收到的所有数据。)
    这里的 received 变量用于记录已经处理了多少个字符,每次 readyState 值为 3 时都递增。
    然后,通过 progress 回调函数来处理传入的新数据。
    而当 readyState 值为 4 时,则执行 finished 回调函数,传入响应返回的全部内容。 */
    function createStreamingClient(url, progress, finished){
    
            var xhr = new XMLHttpRequest(),
                received = 0;
    
            xhr.open("get", url, true);
            xhr.onreadystatechange = function(){
                var result;
    
                if (xhr.readyState == 3){
    
                    //只取得最新数据并调整计数器
                    result = xhr.responseText.substring(received);
                    received += result.length; 
    
                    //调用 progress 回调函数 
                    progress(result);
                } else if (xhr.readyState == 4){
                    finished(xhr.responseText);
            }
        };
        xhr.send(null);
        return xhr;
    }
    var client = createStreamingClient("streaming.php", function(data){                     
                    alert("Received: " + data);
                }, function(data){
                   alert("Done!");
    });

20.SSE(Server-Sent Events,服务器发送事件)API:用于创建到服务器的单向连接,服务器通过这个连接可以发送任意数量的数据。服务器响应的 MIME 类型必须是 text/event-stream,而且是浏览器中的 JavaScript API 能解析格式输出。

首先要创建一个新的 EventSource 对象,并传进一个入口点:

EventSource 对象会保持与服务器的活动连接。如果连接断开,还会重新连接,适合长轮询和 HTTP 流

//传入的 URL 必须与创建对象的页面同源(相同的 URL 模式、域及端口)。
var source = new EventSource("myevents.php");

EventSource 的 实例有一个 readyState 属性:

  • 值为 0 表示正连接到服务器
  • 值为 1 表示打开了连接
  • 值为 2 表示关闭 了连接。

EventSource 的 实例有三个事件:

  • open:在建立连接时触发。
  • message:在从服务器接收到新事件时触发。
  • error:在无法建立连接时触发。

服务器发回的数据以字符串形式保存在 event.data 中

强制立即断开连接并且不再重新连接,可以调用 close() 方法。

 source.close();

21.Web Sockets 是一种与服务器进行全双工、双向通信的信道。不使用 HTTP 协议,而使用一种自定义的协议,未加密是 ws://;加密的连接是 wss://,能够在客户端和服务器之间发送非常少量的数据,而不必担心 HTTP 那样字节级的开销,非常适合移动应用。

  • 要创建 Web Socket,先实例一个 WebSocket 对象并传入要连接的 URL:
//必须给 WebSocket 构造函数传入绝对 URL
var socket = new WebSocket("ws://www.example.com/server.php");
  • 实例化了 WebSocket 对象后,浏览器就会马上尝试创建连接。与 XHR 类似,WebSocket 也有一 个表示当前状态的 readyState 属性:
  1. WebSocket.OPENING (0):正在建立连接。
  2. WebSocket.OPEN (1):已经建立连接。
  3. WebSocket.CLOSING (2):正在关闭连接。
  4. WebSocket.CLOSE (3):已经关闭连接。
  • Web Socket 打开之后,就可以通过 send()方法向服务器发送数据, 但是只能发送纯文本数据,所以对于复杂的数据结构,在发送之前, 必须进行序列化。
  •  var message = {
            time: new Date(),
            text: "Hello world!",
            clientId: "asdfp8734rew"
        };
    socket.send(JSON.stringify(message));
  • 当服务器向客户端发来消息时,WebSocket 对象就会触发 message 事件,把返回的数据保存在 event.data 属性中。
  • //event.data 中返回的数据是字符串
    socket.onmessage = function(event){
            var data = event.data;
            
            //处理数据 
    };
  • 关闭 Web Socket 连接,可以在任何时候调用 close()方法。
  •  socket.close();
  • WebSocket 对象还有其他三个事件,在连接生命周期的不同阶段触发:
  1. open:在成功建立连接时触发。
  2. error:在发生错误时触发,连接不能持续。 
  3. close:在连接关闭时触发。
  • socket.onopen = function(){
        alert("Connection established.");
    };
    socket.onerror = function(){
        alert("Connection error.");
    };
    /*只有 close 事件的 event 对象有额外的信息,事件对象有三个额外的属性:
    wasClean:一个布尔值,表示连接是否已经明确地关闭;
    code:服务器返回的数值状态码;
    reason:一个字符串,包含服务器发回的消息。*/
    socket.onclose = function(event){
        console.log("Was clean? " + event.wasClean + " Code=" + event.code + "Reason="+ event.reason);
    };
    

22. CSRF(Cross-Site Request Forgery,跨站 点请求伪造):未被授权系统伪装自己,让处理请求的服务器认为它是合法的。为确保通过 XHR 访问的 URL 安全,通行的做法就是验证发送请求者是否有权限访问相应的资源。有下列几种方式可供选择:

  • 要求以 SSL 连接来访问可以通过 XHR 请求的资源。
  • 要求每一次请求都要附带经过相应算法计算得到的验证码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值