Javascript高级程序设计第21章(Ajax与Comet)

2024-05-11 11:48

本文主要是介绍Javascript高级程序设计第21章(Ajax与Comet),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

背景:在XHR出现之前,Ajax式的通信必须借助一些hack手段来实现,大多数是使用隐藏的框架或内嵌框架,如window.name,document.domain + iframe,动态创建外域或同域JS,JSONP等等,具体可看这篇文章 JavaScript跨域总结与解决方法

1.兼容性:IE7+、Firefox等主流浏览器都支持原生的XHR对象,在这些浏览器中创建XHR对象,比较简洁的全兼容写法:

var xhr = null;
function createXHR(){if (window.XMLHttpRequest){// 新浏览器xhr = new XMLHttpRequest();}else if (window.ActiveXObject){// IE5,IE6xhr = new ActiveXObject("Microsoft.XMLHTTP");}
}
2.XHR的用法

①在使用XHR对象时,要调用的第一个方法是open(),它接受3个参数:要发送的请求的类型("get", "post"等)、请求的URL和表示是否异步发送请求的布尔值。

xhr.open("get", "example.php", false);

调用open()方法并不会发送请求,而只是启动一个请求以备发送,只能向同一个域中使用相同端口和协议的URL发送请求。如果URL与启动请求的页面有任何茶币,都会引发安全错误。

要发送特定的请求,必须像这样:

xhr.send(null);

如果不需要通过请求主体发送数据,则必须传入null,因为这个参数对有些浏览器来说是必需的。

在收到响应后,响应的数据会自动填充XHR对象的属性

responseText:作为响应主体被返回的问题(常用)

responseXML:如果响应的内容类型是"text/xml"或"application/xml",这个属性中将保存着响应数据的XML DOM文档

status:响应的HTTP状态(常用)HTTP 200~299,响应成功,304使用浏览器缓存

statusText:HTTP状态的说明 200-》ok,跨浏览器不太可靠

②发送异步请求,可以监测XHR对象的readyState属性,该属性表示请求/响应过程中的当前活动阶段

0:未初始化

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

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

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

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

xhr.onreadystatechnage = function(){//....
}

不过我们必须在调用open()之前指定onreadystatechange事件处理程序才能确保浏览器兼容性

1.这里用了DOM 0级方法是因为不需要用到event对象

2.这里没有使用xhr对象是因为DOM 0事件处理程序的作用域问题。如果使用this对象,在有的浏览器中会导致函数执行失败,或者导致错误发生

②HTTP头部信息

使用setRequestHeader()方法可以设置自定义的请求头部信息。这个方法接受两个参数:头部字段的名称和头部字段的值。要成功发送请求头部信息,必须在调用open()方法之后且调用send()方法之前调用setRequestHeader()。最好使用自定义的头部字段名称,不要使用浏览器正常发送的字段名称,否则有可能会影响服务器的相应

xhr.setRequestHeader("myheader", "MyValue")
调用XHR对象的getResponseHeader()方法并传入头部字段名称,可以取得相应的响应头部信息。而调用getAllResponseHeaders()方法则取得一个包含所有头部信息的长字符串

POST请求:与get请求相比,POST请求消耗的资源会更多一些。从性能角度上看,GET请求的速度最多可达到POST请求的两倍

默认情况下,服务器对POST请求和提交Web表单的请求并不会一视同仁。因此,服务器端必须有程序来读取发送过来的原始数据,并从中解析出有用的部分。不过,我们可以使用XHR来模仿表单提交:首先将Cotent-Type头部信息设置为application/x-www-form-urlencoded,也就是表单提交时的内容类型,其次是以适当的格式创建一个字符串

xhr.open("post", "postexample.php", true);xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");var form = document.getElementById("user-info");            xhr.send(serialize(form));

3.XMLHttpRequest 2级

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

var data = new FormData();
data.append("name", "Nicholas");
或者传入表单元素
var data = new FormData(document.forms[0]);

使用FormData的方便之处体现明确地在XHR对象上设置头部

兼容性:主流浏览器,IE 10+、Android 3+版WebKit,这样在移动端就不用担心了


②超时设定:仅支持IE 8+

xhr.open("get", "timeout.php", true);xhr.timeout = 1000;xhr.ontimeout = function(){alert("Request did not return in a second.");};        xhr.send(null);

③overrideMimeType()方法

用于重写XHR相应的MIME类型

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

需必须send()方法之前,才能保证重写相应的MIME类型


③进度事件

6个进度事件

loadstart:在接收到响应数据的第一个字节时触发

progress:在接收响应期间持续不断地触发

error:在请求发生错误时触发

abort:在因为调用abort()方法而终止连接时触发

load:在接受到完整的响应数据时触发

loadend:在通信完成或触发error、abort或load事件后触发(很少浏览器支持)

loadstart -> progress+ -> (error || abort || load) -> loadend 

window.onload = function(){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";}    //position表示已经接收到的字节数,totalSize表示根据Content-Length响应头部确定的预期字节数};xhr.open("get", "altevents.php", true);xhr.send(null);};

为确保正确执行,必须在调用open()方法之前添加onprogress事件处理程序

IE8+只支持load事件,目前还没有浏览器支持loadend事件


4.跨源资源共享

CORS(Cross-Origin Resource Sharing,跨源资源共享),定义了再必须访问跨源资源时,浏览器与服务器应该如何沟通。CORS背后的基本思想,就是使用自定义的HTTP头部让浏览器与服务器进行如何沟通,从而决定请求或响应式应该成功,还是应该失败。比如,浏览器附加一个origin头部 Origin: http://www.nczonline.net ,服务器 Access-Control-Allow-Origin: hhtp://www.nczonline.net,如果没有这个头部,或者有这个头部但源信息不匹配,浏览器就会驳回请求

IE对CORS的实现: XHR(XDomainRequest)

限制:cookie不会随请求发送,也不会随响应返回

只能设置请求头部信息中的Content-Type字段

不能访问响应头部信息

只能设置GET和POST请求

var xdr = new XDomainRequest();xdr.onload = function(){alert(xdr.responseText);};xdr.onerror = function(){alert("Error!");};//you'll need to replace this URL with something that worksxdr.open("get", "http://www.somewhere-else.com/xdr.php");xdr.send(null); //xdr.open("post", ""http://www.baidu.com");
//xdr.contentType = "application/x-www-form-urlencoded";


其他浏览器对CORS的实现:标准的XHR对象 new XMLHttpRequest()

在尝试打开不同来源的资源时,无需额外编写代码就可以出发这个代码。

但跨域XHR对象也有一些限制:

①不能使用setRequestHeader()设置自定义头部

②不能发送和接受cookie

③调用getAllResponseHeaders()方法总会返回空字符串

由于无论同源请求还是跨源请求都使用相同的接口,因此对于本地资源,最好使用相对URL


5.跨浏览器的CORS

即使浏览器对CORS的支持程度并不多一样,但所有浏览器都支持简单的(非Preflight和不带凭据的)请求,因此有必要实现一个跨浏览器的方案。检测XHR是否支持CORS的最简单的方式,就是检查是否存在withCredentials属性。再结合XDomainRequest对象是否存在,就可以兼顾所有浏览器了。

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/xdr.php");if (request){request.onload = function(){//do something with request.responseText};request.send();}
Firefox、Safari和Chrome中的XMLHttpRequest对象与IE中的XDomainRequest对象类似,都提供了足够用的接口,因此以上模式是相当有用的。这两个对象共同的属性/方法如下:

abort():用于停止正在进行的请求

onerror:用于代替onreadystatechange检测错误

onload:代替onreadystatechange检测成功

responseText:用于取得相应内容

send():用于发送请求

以上成员都包含在createCORSRequest()函数返回的对象中,在所有浏览器中都能正常使用


6.其他跨域技术

①图像ping:使用<img>标签,是在线广告跟踪浏览量的主要方式。

方式:单向,动态创建图像,使用onload和onerror事件处理程序来确定是否接收到了响应。请求的数据是通过查询字符串(如url?test=hello)发送的,而响应可以是任意内容,但通常是像素图或204响应

解释:204响应是指服务器成功处理了客户端的请求,但服务器无返回响应,即Content-Length为0,因为客户端只管把数据发送给服务器,无需关心响应,详情戳点击打开链接

var img = new Image();img.onload = img.onerror = function(){alert("Done!");};img.src = "http://www.example.com/test?name=Nicholas"; 

用途:图像Ping最常用于跟踪用户点击页面或动态广告曝光次数。

缺点:只能发送GET请求,二是无法返回服务器的响应文本。


②JSONP:JSON with padding

JSONP和JSON看起来差不多,只不过是被包含在函数调用中的JSON,如callback({"name": "Nicholas"});

JSONP由两部分组成:回调函数和数据。回调函数是当响应到来时在页面中调用的函数。回调函数的名字一般是在请求中指定。而数据就是传入函数中的JSON数据

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);
JSONP与图像Ping对比的优点是:能够直接访问响应文本,支持在浏览器与服务器之间双向通信。

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

另外,要确定JSONP请求是否失败并不容易,虽然HTML5给<script>元素新增了一个onerror事件处理程序,但目前还没有得到任何浏览器支持。为此,开发人员不得部使用计时器检测指定时间内是否接收到了响应


7.Comet

Comet:服务器推送。刚好与Ajax相反,Ajax是一种从页面向服务器请求数据的技术,而Comet则是一种服务器向页面推送数据的技术。Comet能够让信息近乎实时地被推送到页面上,非常适合处理体育比赛的分数和股票涨价。

有两种实现Comet的方式:长轮询和流。

①长轮询是传统轮询(也成为短轮询,浏览器定时向服务器发送请求,看有没有更新的数据)的一个翻版,长轮询把段轮训颠倒了一下。页面发起一个到服务器的请求,然后服务器一直保持连接打开,直到有数据可发送。发送完了数据,浏览器关闭连接,随即又发送一个到服务器的新请求。

它们的区别在于服务器如何发送数据,短轮询是服务器立即发送响应,无论数据是否有效,而长轮询是等待发送响应。轮询的优势有所有浏览器都支持,因为使用XHR对象和setTimeout()就能实现。而你要做的就是决定什么时候发送请求。

②HTTP流,与轮询不同,因为它在页面的整个生命周期只使用一个HTTP连接。具体来说,就是浏览器向服务器发送一个请求,而服务器保持连接打开,然后周期性地向浏览器发送数据。

<?php$i = 0;while(true){//输出一些数据,然后立即刷新输出缓存echo "Number is $i";flush();//等几秒钟sleep(10);$i++     }

所有服务器语言都支持打印到输出缓存然后刷新(将输出缓存中的内容一次性全部发送给客户端)的功能。
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){//get only the new data and adjust counterresult = xhr.responseText.substring(received);received += result.length;//call the progress callbackprogress(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!");});
在Firefox、safari、Opera和Chrome中,通过侦听readystatechange事件及检测readyState的值是否为3,就可以利用XHR对象实现HTTP流。有时候,当连接关闭时,很肯呢过还需要重新连接,所以关注连接什么时候关闭时很有必要的。这个例子比较简单,而且也能在大多数浏览器正常运行(除IE),但管理Comet的连接时很容易出错的,需要时间不断改进才能达到完美。


8.服务器发送事件

SSE(Server-Sent-Event,服务器发送事件),因为兼容非常有限,所以不详细说了。

Web Sockets:使用自定义协议,适合移动应用,IOS上应用没问题,但Android就呵呵了

这篇关于Javascript高级程序设计第21章(Ajax与Comet)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/979449

相关文章

Java实现检查多个时间段是否有重合

《Java实现检查多个时间段是否有重合》这篇文章主要为大家详细介绍了如何使用Java实现检查多个时间段是否有重合,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录流程概述步骤详解China编程步骤1:定义时间段类步骤2:添加时间段步骤3:检查时间段是否有重合步骤4:输出结果示例代码结语作

Java中String字符串使用避坑指南

《Java中String字符串使用避坑指南》Java中的String字符串是我们日常编程中用得最多的类之一,看似简单的String使用,却隐藏着不少“坑”,如果不注意,可能会导致性能问题、意外的错误容... 目录8个避坑点如下:1. 字符串的不可变性:每次修改都创建新对象2. 使用 == 比较字符串,陷阱满

Java判断多个时间段是否重合的方法小结

《Java判断多个时间段是否重合的方法小结》这篇文章主要为大家详细介绍了Java中判断多个时间段是否重合的方法,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录判断多个时间段是否有间隔判断时间段集合是否与某时间段重合判断多个时间段是否有间隔实体类内容public class D

IDEA编译报错“java: 常量字符串过长”的原因及解决方法

《IDEA编译报错“java:常量字符串过长”的原因及解决方法》今天在开发过程中,由于尝试将一个文件的Base64字符串设置为常量,结果导致IDEA编译的时候出现了如下报错java:常量字符串过长,... 目录一、问题描述二、问题原因2.1 理论角度2.2 源码角度三、解决方案解决方案①:StringBui

Java覆盖第三方jar包中的某一个类的实现方法

《Java覆盖第三方jar包中的某一个类的实现方法》在我们日常的开发中,经常需要使用第三方的jar包,有时候我们会发现第三方的jar包中的某一个类有问题,或者我们需要定制化修改其中的逻辑,那么应该如何... 目录一、需求描述二、示例描述三、操作步骤四、验证结果五、实现原理一、需求描述需求描述如下:需要在

Java中ArrayList和LinkedList有什么区别举例详解

《Java中ArrayList和LinkedList有什么区别举例详解》:本文主要介绍Java中ArrayList和LinkedList区别的相关资料,包括数据结构特性、核心操作性能、内存与GC影... 目录一、底层数据结构二、核心操作性能对比三、内存与 GC 影响四、扩容机制五、线程安全与并发方案六、工程

JavaScript中的reduce方法执行过程、使用场景及进阶用法

《JavaScript中的reduce方法执行过程、使用场景及进阶用法》:本文主要介绍JavaScript中的reduce方法执行过程、使用场景及进阶用法的相关资料,reduce是JavaScri... 目录1. 什么是reduce2. reduce语法2.1 语法2.2 参数说明3. reduce执行过程

如何使用Java实现请求deepseek

《如何使用Java实现请求deepseek》这篇文章主要为大家详细介绍了如何使用Java实现请求deepseek功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1.deepseek的api创建2.Java实现请求deepseek2.1 pom文件2.2 json转化文件2.2

Java调用DeepSeek API的最佳实践及详细代码示例

《Java调用DeepSeekAPI的最佳实践及详细代码示例》:本文主要介绍如何使用Java调用DeepSeekAPI,包括获取API密钥、添加HTTP客户端依赖、创建HTTP请求、处理响应、... 目录1. 获取API密钥2. 添加HTTP客户端依赖3. 创建HTTP请求4. 处理响应5. 错误处理6.

Spring AI集成DeepSeek的详细步骤

《SpringAI集成DeepSeek的详细步骤》DeepSeek作为一款卓越的国产AI模型,越来越多的公司考虑在自己的应用中集成,对于Java应用来说,我们可以借助SpringAI集成DeepSe... 目录DeepSeek 介绍Spring AI 是什么?1、环境准备2、构建项目2.1、pom依赖2.2