`

向服务器请求数据的五种技术

 
阅读更多

Ajax,在它最基本的层面,是一种与服务器通讯而不重载当前页面的方法,数据可从服务器获得或发送给服务器。有多种不同的方法构造这种通讯通道,每种方法都有自己的优势和限制。
      有五种常用技术用于向服务器请求数据:
      (1)XMLHttpRequest (XHR)
      (2)动态脚本标签插入
      (3)框架
      (4)Comet
      (5)多部分的XHR
      在现代高性能JavaScript中使用的三种技术是XHR,动态脚本标签插入和多部分的XHR。使用Comet和iframe(作为数据传输技术)往往是极限情况,不在这里讨论。

      一、XMLHttpRequest
      目前最常用的方法中,XMLHttpRequest(XHR)用来异步收发数据。所有现代浏览器都能够很好地支持它,而且能够精细地控制发送请求和数据接收。你可以向请求报文中添加任意的头信息和参数(包括GET和POST),并读取从服务器返回的头信息,以及响应文本自身。以下是使用示例:
      var url = '/data.php';
      var params = [
            'id=934875',
            'limit=20'
      ];
      var req = new XMLHttpRequest();
      req.onreadystatechange = function() {
            if (req.readyState=== 4) {
                  var responseHeaders = req.getAllResponseHeaders();
                  var data = req.responseText;
            }
      }
      req.open('GET', url + '?' + params.join('&'), true);
      req.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
      req.send(null);
      此例显示了如何从URL请求数据,使用参数,以及如何读取响应报文和头信息。readyState等于4表示整个响应报文已经收并完可用于操作。
      readyState等于3则表示此时正在与服务器交互,响应报文还在传输之中。这就是所谓的“流”,它是提高数据请求性能的强大工具:
      req.onreadystatechange = function() {
            if (req.readyState=== 3) {
                  var dataSoFar = req.responseText;
                  …
            }
            else if (req.readyState=== 4) {
                  var data = req.responseText;
                  …
            }
      }
      由于XHR提供了高级别的控制,浏览器在上面增加了一些限制。你不能使用XHR从当前运行的代码域之外请求数据,而且老版本的IE 也不提供readyState3,它不支持流。从请求返回的数据像一个字符串或者一个XML对象那样对待,这意味着处理大量数据将相当缓慢。
尽管有这些缺点,XHR仍旧是最常用的请求数据技术,也是最强大的,它应当成为你的首选。
      当使用XHR请求数据时,你可以选择POST 或GET。如果请求不改变服务器状态只是取回数据(又称作幂等动作)则使用GET。GET请求被缓冲起来,如果你多次提取相同的数据可提高性能。
      只有当URL和参数的长度超过了2'048个字符时才使用POST提取数据。因为Internet Explorer限制URL的长度,过长将导致请求(参数)被截断。
      二、动态脚本标签插入
      该技术克服了XHR的最大限制:它可以从不同域的服务器上获取数据。这是一种黑客技术,而不是实例化一个专用对象,你用JavaScript创建了一个新脚本标签,并将它的源属性设置为一个指向不同域的URL。
      var scriptElement = document.createElement('script');
      scriptElement.src = 'http://any-domain.com/javascript/lib.js';
      document.getElementsByTagName_r('head')[0].appendChild(scriptElement);
      但是动态脚本标签插入与XHR相比只提供更少的控制。你不能通过请求发送信息头。参数只能通过GET方法传递,不能用POST。你不能设置请求的超时或重试,实际上,你不需要知道它是否失败了。你必须等待所有数据返回之后才可以访问它们。你不能访问响应信息头或者像访问字符串那样访问整个响应报文。
      最后一点非常重要。因为响应报文被用作脚本标签的源码,它必须是可执行的JavaScript。你不能使用裸XML,或者裸JSON,任何数据,无论什么格式,必须在一个回调函数之中被组装起来。
      var scriptElement = document.createElement('script');
      scriptElement.src = 'http://any-domain.com/javascript/lib.js';
      document.getElementsByTagName_r('head')[0].appendChild(scriptElement);
      function jsonCallback(jsonString) {
            var data = ('(' + jsonString + ')');
      }
      在这个例子中,lib.js 文件将调用jsonCallback 函数组装数据:
      jsonCallback({ "status": 1, "colors": [ "#fff", "#000", "#ff0000" ] });
      尽管有这些限制,此技术仍然非常迅速。其响应结果是运行JavaScript,而不是作为字符串必须被进一步处理。正因为如此,它可能是客户端上获取并解析数据最快的方法。我们比较了动态脚本标签插入和XHR的性能,在本章后面JSON 一节中。
      请小心使用这种技术从你不能直接控制的服务器上请求数据。JavaScript没有权限或访问控制的概念,所以你的页面上任何使用动态脚本标签插入的代码都可以完全控制整个页面。包括修改任何内容、将用户重定向到另一个站点,或跟踪他们在页面上的操作并将数据发送给第三方。使用外部来源的代码时务必非常小心。
      三、多部分XHR
      多部分XHR(MXHR)允许你只用一个HTTP 请求就可以从服务器端获取多个资源。它通过将资源(可以是CSS 文件,HTML 片段,JavaScript代码,或base64 编码的图片)打包成一个由特定分隔符界定的大字符串,从服务器端发送到客户端。JavaScript代码处理此长字符串,根据它的媒体类型和其他“信息头”解析出每个资源。
      让我们从头到尾跟随这个过程。首先,发送一个请求向服务器索取几个图像资源:
      var req = new XMLHttpRequest();
      req.open('GET', 'rollup_images.php', true);
      req.onreadystatechange = function() {
            if (req.readyState== 4) {
                  splitImages(req.responseText);
            }
      };
      req.send(null);
      这是一个非常简单的请求。你向rollup_images.php 要求数据,一旦你收到返回结果,就将它交给函数splitImages处理。
      下一步,服务器读取图片并将它们转换为字符串:
      $images = array('kitten.jpg', 'sunset.jpg', 'baby.jpg');
      foreach ($images as $image) {
            $image_fh = fopen($image, 'r');
            $image_data = fread($image_fh, filesize($image));
            fclose($image_fh);
            $payloads[] = base64_encode($image_data);
      }
      $newline = chr(1);
      echo implode($newline, $payloads);
      这段PHP代码读取三个图片,并将它们转换成base64字符串。它们之间用一个简单的字符,UNICODE的1,连接起来,然后返回给客户端。
      然后回到客户端,此数据由splitImage 函数处理:
      function splitImages(imageString) {
            var imageData = imageString.split("\u0001");
            var imageElement;
            for (var i = 0, len = imageData.length; i < len; i++) {
                  imageElement = document.createElement('img');
                  imageElement.src = 'data:image/jpeg;base64,' + imageData[i];
                  document.getElementById('container').appendChild(imageElement);
            }
      }
      此函数将拼接而成的字符串分解为三段。每段用于创建一个图像元素,然后将图像元素插入页面中。图像不是从base64 转换成二进制,而是使用data:URL 并指定image/jpeg 媒体类型。
      最终结果是:在一次HTTP 请求中向浏览器传入了三张图片。也可以传入20 张或100 张,响应报文会更大,但也只是一次HTTP 请求。它也可以扩展至其他类型的资源。JavaScript文件,CSS 文件,HTML片段,许多类型的图片都可以合并成一次响应。任何数据类型都可作为一个JavaScript处理的字符串被发送。下面的函数用于将JavaScript代码、CSS 样式表和图片转换为浏览器可用的资源:
      function handleImageData(data, mimeType) {
            var img = document.createElement('img');
            img.src = 'data:' + mimeType + ';base64,' + data;
            return img;
      }
      function handleCss(data) {
            var style = document.createElement('style');
            style.type = 'text/css';
            var node = document.createTextNode(data);
            style.appendChild(node);
            document.getElementsByTagName_r('head')[0].appendChild(style);
      }
      function handleJavaScript(data) {
            (data);
      }
      由于MXHR响应报文越来越大,有必要在每个资源收到时立刻处理,而不是等待整个响应报文接收完成。这可以通过监听readyState3 实现:
      var req = new XMLHttpRequest();
      var getLatestPacketInterval, lastLength = 0;
      req.open('GET', 'rollup_images.php', true);
      req.onreadystatechange = readyStateHandler;
      req.send(null);
      function readyStateHandler{
            if (req.readyState=== 3 && getLatestPacketInterval === null) {
                  getLatestPacketInterval = window.setInterval(function() {
                        getLatestPacket();
                  }, 15);
            }
            if (req.readyState=== 4) {
                  clearInterval(getLatestPacketInterval);
                  getLatestPacket();
            }
      }
      function getLatestPacket() {
            var length = req.responseText.length;
            var packet = req.responseText.substring(lastLength, length);
            processPacket(packet);
            lastLength = length;
      }
      当readyState3第一次发出时,启动了一个定时器。每隔15毫秒检查一次响应报文中的新数据。数据片段被收集起来直到发现一个分隔符,然后一切都作为一个完整的资源处理。以健壮的方式使用MXHR的代码很复杂但值得进一步研究。
      使用此技术有一些缺点,其中最大的缺点是以此方法获得的资源不能被浏览器缓存。如果你使用MXHR获取一个特定的CSS 文件然后在下一个页面中正常加载它,它不在缓存中。因为整批资源是作为一个长字符串传输的,然后由JavaScript代码分割。由于没有办法用程序将文件放入浏览器缓存中,所以用这种方法获取的资源也无法存放在那里。
      另一个缺点是:老版本的Internet Explorer不支持readyState3或data: URL。Internet Explorer 8两个都支持,但在Internet Explorer 6和7中必须设法变通。
      尽管有这些缺点,但某些情况下MXHR仍然显著提高了整体页面的性能:网页包含许多其他地方不会用到的资源(所以不需要缓存),尤其是图片。
      网站为每个页面使用了独一无二的打包的JavaScript或CSS文件以减少HTTP请求,因为它们对每个页面来说是独一的,所以不需要从缓存中读取,除非重新载入特定页面。
      由于HTTP请求是Ajax中最极端的瓶颈之一,减少其需求数量对整个页面性能有很大影响。尤其是当你将100个图片请求转化为一个MXHR请求时。Ad hoc 在现代浏览器上测试了大量图片,其结果显示出此技术比逐个请求快了4到10倍。
      有时你不关心接收数据,而只要将数据发送给服务器。你可以发送用户的非私有信息以备日后分析,或者捕获所有脚本错误然后将有关细节发送给服务器进行记录和提示。当数据只需发送给服务器时,有两种广泛应用的技术:XHR和灯标。
      (1) XMLHttpRequest
      虽然XHR主要用于从服务器获取数据,它也可以用来将数据发回。数据可以用GET或POST 方式发回,以及任意数量的HTTP 信息头。这给你很大灵活性。当你向服务器发回的数据量超过浏览器的最大URL长度时XHR特别有用。这种情况下,你可以用POST 方式发回数据:
      var url = '/data.php';
      var params = [
            'id=934875',
            'limit=20'
      ];
      var req = new XMLHttpRequest();
      req.onerror = function() {
            // Error.
      };
      req.onreadystatechange = function() {
            if (req.readyState== 4) {
                  // Success.
            }
      };
      req.open('POST', url, true);
      req.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
      req.setRequestHeader('Content-Length', params.length);
      req.send(params.join('&'));
      正如你在这个例子中看到的,如果失败了我们什么也不做。当我们用XHR捕获登陆用户统计信息时这么做通常没什么问题,但是,如果发送到服务器的是至关重要的数据,你可以添加代码在失败时重试:
      function xhrPost(url, params, callback) {
            var req = new XMLHttpRequest();
            req.onerror = function() {
                  setTimeout(function() {
                        xhrPost(url, params, callback);
                  }, 1000);
            };
            req.onreadystatechange = function() {
                  if (req.readyState== 4) {
                        if (callback && typeof callback === 'function') {
                             callback();
                        }
                  }
            };
            req.open('POST', url, true);
            req.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
            req.setRequestHeader('Content-Length', params.length);
            req.send(params.join('&'));
      }
      当使用XHR将数据发回服务器时,它比使用GET要快。这是因为对少量数据而言,向服务器发送一个GET请求要占用一个单独的数据包。另一方面,一个POST至少发送两个数据包,一个用于信息头。另一个用于POST体。POST更适合于向服务器发送大量数据,即因为它不关心额外数据包的数量,又因为Internet Explorer 的URL长度限制,它不可能使用过长的GET请求。
      (2) 灯标
      此技术与动态脚本标签插入非常类似。JavaScript用于创建一个新的Image 对象,将src 设置为服务器上一个脚本文件的URL。此URL 包含我们打算通过GET格式传回的键值对数据。注意并没有创建img 元素或者将它们插入到DOM 中。
      var url = '/status_tracker.php';
      var params = [
            'step=2',
            'time=1248027314'
      ];
      (new Image()).src = url + '?' + params.join('&');
      服务器取得此数据并保存下来,而不必向客户端返回什么,因此没有实际的图像显示。这是将信息发回服务器的最有效方法。其开销很小,而且任何服务器端错误都不会影响客户端。
      简单的图像灯标意味着你所能做的受到限制。你不能发送POST 数据,所以你被URL 长度限制在一个相当小的字符数量上。你可以用非常有限的方法接收返回数据。可以监听Image 对象的load 事件,它可以告诉你服务器端是否成功接收了数据。你还可以检查服务器返回图片的宽度和高度(如果返回了一张图片)并用这些数字通知你服务器的状态。例如,宽度为1 表示“成功”,2 表示“重试”。
      如果你不需要为此响应返回数据,那么你应当发送一个204 No Content 响应代码,无消息正文。它将阻止客户端继续等待永远不会到来的消息体:
      var url = '/status_tracker.php';
      var params = [
            'step=2',
            'time=1248027314'
      ];
      var beacon = new Image();
      beacon.src = url + '?' + params.join('&');
      beacon.onload = function() {
            if (this.width == 1) {
                  // Success.
            }
            else if (this.width == 2) {
                  // Failure; create another beacon and try again.
            }
      };
      beacon.onerror = function() {
            // Error; wait a bit, then create another beacon and try again.
      };
      灯标是向服务器回送数据最快和最有效的方法。服务器根本不需要发回任何响应正文,所以你不必担心客户端下载数据。唯一的缺点是接收到的响应类型是受限的。如果你需要向客户端返回大量数据,那么使用XHR。如果你只关心将数据发送到服务器端(可能需要极少的回复),那么使用图像灯标。

原创文章,转载请注明: 转载自http://www.yiiyaa.net/
本文链接地址: http://www.yiiyaa.net/1229
分享到:
评论

相关推荐

    基于指数平滑的云服务器请求量集成预测模型.pdf

    5. 线性回归模型在预测中的应用:线性回归是一种统计方法,能够分析因变量(这里指云服务器请求量)与一个或多个自变量(如时间序列数据)之间的关系,通过最小化误差的平方和来进行模型的预测。 6. 平滑系数的动态...

    asp.net 服务器推技术源码

    ASP.NET服务器推技术是一种允许服务器主动向客户端发送数据的技术,而不是传统的HTTP协议中客户端发起请求、服务器响应的方式。在Web开发中,服务器推技术能够实现实时性更强的应用场景,如在线聊天、股票实时更新、...

    WEB开发 之 AJAX - 向服务器发送请求.docx

    在AJAX中,我们可以使用GET请求和POST请求两种方式向服务器发送请求。GET请求适用于大部分情况下,但是当我们需要向服务器发送大量数据或更新服务器上的文件或数据库时,需要使用POST请求。 GET请求的特点是简单、...

    安卓和服务器数据交换

    HTTP允许客户端向服务器发送请求,获取或提交数据。HTTPS则在HTTP基础上加入了SSL/TLS加密,确保数据传输的安全性。 6. **Http通信**:在安卓中,使用HttpURLConnection或OkHttp等库可以实现HTTP通信。开发者需要...

    WWW服务器与SQL服务器互联技术.pdf

    CGI 程序运行机制主要包括以下几个步骤:浏览器向 WWW 服务器发出请求,WWW 服务器将请求传递给 CGI 程序,CGI 程序将请求传递给 SQL 服务器,SQL 服务器将结果传递回 CGI 程序,CGI 程序将结果传递回 WWW 服务器,...

    行业分类-设备装置-一种对象数据服务器读写请求的调度方法.zip

    "一种对象数据服务器读写请求的调度方法"是针对这一问题提出的一种创新解决方案,旨在提升服务器性能,降低延迟,优化资源分配,确保系统稳定运行。 首先,我们需要理解“对象数据服务器”。对象数据服务器是一种...

    电信设备-包含用于向提出请求的蜂窝移动站提供用户化服务的代码的服务器请求.zip

    综上所述,"电信设备-包含用于向提出请求的蜂窝移动站提供用户化服务的代码的服务器请求.zip"这一主题涵盖了移动通信、服务器架构、网络安全、数据处理、用户体验等多个方面的IT知识,展示了现代通信系统中复杂而...

    android客户端连接远程服务器传递数据

    远程服务器上使用 Servlet 来处理客户端的请求,并返回 JSON 数据给客户端。 Android 客户端连接远程服务器传递数据的步骤: 1. Android 客户端使用 HTTP 协议连接远程服务器,发送请求到 Servlet。 2. Servlet ...

    webapi接口请求数据防篡改

    "webapi接口请求数据防篡改"是一个核心问题,它涉及到如何确保在客户端与服务器之间传输的数据不被中间人攻击或其他恶意行为篡改。在这个场景下,我们通常会采用数据签名的技术来保证数据的完整性。 数据签名是一种...

    springmvc+spring线程池处理http并发请求数据同步控制问题

    在这个主题中,我们将深入探讨如何利用Spring MVC与Spring线程池来有效地管理并发请求,并解决数据同步控制问题。 一、Spring MVC与并发处理 1. Spring MVC通过DispatcherServlet接收HTTP请求,然后根据映射规则将...

    WEB服务器日志数据

    在IT行业中,Web服务器日志数据是至关重要的资源,它记录了服务器与用户之间的交互细节,为各种分析和优化提供基础。"WEB服务器日志数据"这个主题涉及到的知识点广泛,包括日志文件的结构、内容、分析方法以及其在...

    Android手机访问服务器的一种数据交互方法

    本文将详细解析一种适用于Android设备与服务器之间数据交互的方法,并结合具体的技术细节进行阐述。 #### 一、概述 在Android应用程序中,实现与服务器的数据交互主要涉及网络请求、数据处理及安全性等方面。本...

    DelphiXE + idHttp和HttpServer + 当客户端与服务器作数据传输的实例+(源码+测试可用)

    在服务器端,HttpServer接收到请求后,会调用预先设定的处理函数,解析请求数据并做出响应。这种模式适用于文件上传、文本消息传递等多种场景。 在提供的源码中,"UnitHttpExample"应该是客户端的代码,它使用...

    android手机与asp服务器传输数据源码

    总结来说,实现“android手机与asp服务器传输数据源码”涉及服务器端的ASP编程、数据库操作以及客户端的Android网络请求和JSON数据处理。理解这些技术以及它们之间的协作,是成功构建这种系统的关键。通过深入学习和...

    服务器推技术入门

    服务器推技术是网络应用中的一种重要机制,它与传统的客户端请求、服务器响应的HTTP协议模型不同,服务器推技术允许服务器主动地将数据推送给客户端,而无需客户端发起新的请求。这种技术在实时性要求较高的场景中,...

    用MFC实现客户端向服务器传送文件

    使用`listen()`函数设置服务器为监听模式,然后`accept()`函数接收客户端的连接请求。一旦有连接,服务器也可以创建一个套接字来处理这个连接。接收到数据后,服务器端同样使用`recv()`函数来接收客户端发送的数据,...

    html通过 ajax jsonp跨域请求接收和传送数据

    这时,HTML通过AJAX和JSONP技术可以实现跨域请求来接收和传送数据。下面将详细讲解这两个概念及其工作原理。 **HTML和AJAX** HTML(HyperText Markup Language)是网页的基础,用于构建网页结构。AJAX...

    服务器推送技术

    在传统的HTTP协议中,客户端(如浏览器)需要主动向服务器发送请求获取数据,而服务器推送技术则允许服务器在客户端未发起请求时主动将数据发送到客户端。这种技术在实时性要求高的应用中,如在线聊天、股票交易、...

Global site tag (gtag.js) - Google Analytics