发新话题
打印

Ajax 传输方法: XMLHttp (2)

Ajax 传输方法: XMLHttp (2)

构建客户机

现在有了客户机可用的数据,还必须决定如何使用三种 Ajax 方法从服务器读取数据。图 1 显示了数据格式和使用这些数据的不同传输方法。


图 1. Ajax 传输兼容表


表面上看,XMLHttp 传输方法似乎是最佳选择。但是由于浏览器中的安全问题,还必须了解两种替代方法。下面几节介绍传输机制,描述用于消费各种数据类型的客户端代码。

XMLHttp 客户机

XMLHttp 方法很容易与 Web 服务器交换数据。它支持 GET 和 POST 方法,因此可以传输大量数据。此外,目前所有浏览器都支持它。

注意:Internet Explorer 需要一些小技巧来获得与 XMLHttp 等价的对象,不过 Internet Explorer 的新版本(版本 7)将支持 Firefox、Opera、Safari 和其他浏览器支持的标准方法。为了解决 Safari 缓冲 XMLHttp 请求的问题,可以添加一个随机值作为 URL 参数来避免缓冲。

XMLHttp 方法的最大优点在于其简单性。最大缺点是对域的安全限制。如果网页来自 www.mysite.com,那么脚本就能从 www.cnn.com 甚至 data.mysite.com 请求数据。只能向 www.mysite.com 发出请求,这就意味着在客户机上创建 RSS 阅读器是不可能的。在服务器上需要代理页面从 www.cnn.com 检索数据,然后通过 www.mysite.com 返回这些数据。

但是先假设安全限制对您来说并不重要。那么如何获取数据呢?

通过 XMLHttp 使用文本服务


清单 20 中的 DHTML 代码从 text.php 检索数据并将它们显示在浏览器中。

清单 20. Http_text.html
                    
<html>
  <title>Text test</title>
    <head>
      <script>
        var req = null;
        function processReqChange()
        {
          if (req.readyState == 4 && req.status == 200 )
          {
            var dobj = document.getElementById( "dataDiv" );
            var text = req.responseText;
            text = text.replace( "\n", "<br/>" );
            dobj.innerHTML = text;
          }
        }

        function loadUrl( url )
        {
          if(window.XMLHttpRequest) {
            try { req = new XMLHttpRequest();
            } catch(e) { req = false; }
          }
          else if(window.ActiveXObject)
          {
            try { req = new ActiveXObject("Msxml2.XMLHTTP");
            } catch(e) {
            try { req = new ActiveXObject("Microsoft.XMLHTTP");
            } catch(e) { req = false; }
          }
        }

          if(req) {
            req.onreadystatechange = processReqChange;
            req.open("GET", url, true);
            req.send("");
          }
        }

        var url = window.location.toString();
        url = url.replace( /\/.*?$/, "sources/text.php" );
        loadUrl( url );
      </script>
    <body>
      <div id="dataDiv">
      </div>
    </body>
</html>

图 2 显示了结果。

图 2. http_text 测试页


这可能是最简单的 XMLHttp 请求。loadUrl 函数创建一个 XMLHttpRequest 对象,然后使用 open 函数开始数据下载。处理完成后,将调用 processReqChange 函数检查请求的状态。如果请求完成,该函数通过 dataDiv 元素将文本添加到 HTML 文档中。正则表达式将文本中的回车换行替换为 <br> 标记,这样文本流看起来就很自然,而不是长长的一行。

通过 XMLHttp 使用 HTML 服务

使用 XMLHttp 对象的另一种常见方法是从服务器请求更新的 HTML 标记数据。Microsoft 的新 Atlas 框架就采用了这种方法。其思路是,当更新页面的一部分时,页面返回服务器以请求新的 HTML,然后更新包含该 HTML 片段的那部分页面。清单 21 显示了这种处理方法。

清单 21. Http_html.html

                    
<html>
  <title>HTML test</title>
    <head>
      <style>
        td { border: 1px solid #666; padding: 3px; }
      </style>
      <script>
        var req = null;
        function processReqChange()
        {
          if (req.readyState == 4 && req.status == 200 )
          {
            var dobj = document.getElementById( "dataDiv" );
            dobj.innerHTML = req.responseText;
          }
        }

        function loadUrl( url )
        {
          ...
        }

        var url = window.location.toString();
        url = url.replace( /\/.*?$/, "sources/html.php" );
          loadUrl( url );
      </script>
    <body>
      <div id="dataDiv">
      </div>
    </body>
</html>

loadUrl 代码和 清单 20 相同。主要区别是 processReqChange 函数使用 responseText 函数填充 dataDiv 元素的 innerHTML,从而更新页面内容。

通过 XMLHttp 使用 XML 和 RSS 服务


到目前为止,XMLHttp 对象最常见的用法是向浏览器传输给定格式的 XML。因为返回的请求对象有内置的 XML 文档对象模型(DOM)元素,可用它搜索 XML 中的新数据。

清单 22 显示了使用定制的 XML 格式从服务器请求图书数据的 DHTML 代码。

清单 22. Http_xml.html
                    
<html>
  <title>XML test</title>
    <head>
      <script>
        var req = null;
        function processReqChange()
        {
          if (req.readyState == 4 && req.status == 200 && req.responseXML )
          {
            var dobj = document.getElementById( "dataBody" );

            var nl = req.responseXML.getElementsByTagName( 'book' );
            for( var i = 0; i < nl.length; i++ )
            {
                    var nli = nl.item( i );
              var elAuthor = nli.getElementsByTagName( 'author' );
              var author = elAuthor.item(0).firstChild.nodeValue;
              var elTitle = nli.getElementsByTagName( 'title' );
              var title = elTitle.item(0).firstChild.nodeValue;

              var elTr = document.createElement( 'tr' );
              dobj.appendChild( elTr );

              var elAuthorTd = document.createElement( 'td' );
              elAuthorTd.innerHTML = author;
              elTr.appendChild( elAuthorTd );

              var elTitleTd = document.createElement( 'td' );
              elTitleTd.innerHTML = title;
              elTr.appendChild( elTitleTd );
            }
          }
        }

        function loadXMLDoc( url )
        {
          ...
        }

            var url = window.location.toString();
            url = url.replace( /\/.*?$/, "sources/xml.php" );
            loadXMLDoc( url );
      </script>
    <body>
      <table cellspacing="0" cellpadding="3">
         <tbody id="dataBody">
         </tbody>
      </table>
    </body>
</html>


(loadXMLDoc 函数和上例中的 loadUrl 相同,为简便起见,我们将它省略了。)巧妙之处在于 processReqChange 函数,其中的 JavaScript 代码使用 getElementsByTagName 函数查找 XML 中的 <book>、<title> 和 <author> 标记。图 3 显示了输出结果。

图 3. 完成的 http_xml 页面


清单 23 显示了解析 RSS 版本的 processReqChange 代码。

清单 23. http_rss.html 中的 processReqChange
                 
...
function processReqChange()
{
  if (req.readyState == 4 && req.status == 200 && req.responseXML )
  {
    var dobj = document.getElementById( "dataBody" );

    var nl = req.responseXML.getElementsByTagName( 'item' );
    for( var i = 0; i < nl.length; i++ )
    {
      var nli = nl.item( i );
      var elDescription = nli.getElementsByTagName( 'description' );
      var description = elDescription.item(0).firstChild.nodeValue;
      var elTitle = nli.getElementsByTagName( 'title' );
      var title = elTitle.item(0).firstChild.nodeValue;
      var elLink = nli.getElementsByTagName( 'link' );
      var link = elLink.item(0).firstChild.nodeValue;

      var elTr = document.createElement( 'tr' );
      dobj.appendChild( elTr );

      var elTitleTd = document.createElement( 'td' );
      elTr.appendChild( elTitleTd );

      var elLink = document.createElement( 'a' );
      elLink.innerHTML = title;
      elLink.href = link;
      elTitleTd.appendChild( elLink );

      var elDescriptionTd = document.createElement( 'td' );
      elDescriptionTd.innerHTML = description;
      elTr.appendChild( elDescriptionTd );
      }
    }
  }
    ...

这里最大的区别是代码发现额外的链接并用它在表中围绕着标题创建了一个 <anchor> 标记。结果如 图 4 所示。


图 4. 完成的 http_rss.html 页面



使用 RSS 传输的优点体现在两方面。首先,RSS 客户机可以监控 RSS;其次,可以将这段 HTML 和 JavaScript 代码应用于任何 RSS 格式的提要,只要数据来自服务页面的同一个域。

通过 XMLHttp 使用 JavaScript 代码和 JSON 服务

为了完成关于 XMLHttp 传输方法的讨论,还要使用 JavaScript 格式的数据。第一个例子(清单 24)显示了处理 js.php 页面数据的 processReqChange 函数,该页面返回 JavaScript 代码(或者 JSON,如果您想赶时髦的话)。

清单 24. http_js.html 页面中的 processReqChange                    
...
  function processReqChange()
  {
    if (req.readyState == 4 && req.status == 200 && req.responseText )
    {
      var books = eval( req.responseText );

      var dobj = document.getElementById( "dataBody" );
      for( var b in books )
      {
      var elTr = document.createElement( 'tr' );
      dobj.appendChild( elTr );

      var elTitleTd = document.createElement( 'td' );
      elTitleTd.innerHTML = books.author;
      elTr.appendChild( elTitleTd );

      var elDescriptionTd = document.createElement( 'td' );
      elDescriptionTd.innerHTML = books.title;
      elTr.appendChild( elDescriptionTd );
      }
    }
  }
...


注意,与解析 XML 相比,解析 js.php 返回的 JavaScript 代码是多么容易。只需要对代码运行 eval 函数并获得返回值,该返回值是一个散列表数组,然后使用标准的 JavaScript for 循环遍历该数组。

传输 JavaScript 代码的另一种方法是使用 清单 16 所示的 JavaScript 代码类型,在求值过程中调用 JavaScript 函数。解析该函数的 JavaScript 代码如 清单 25 所示。

清单 25. http_jsadd.html 中的 processReqChange 和 addData
                    
...
  function addData( url, books )
  {
    var dobj = document.getElementById( "dataBody" );
    for( var b in books )
    {
      var elTr = document.createElement( 'tr' );
      dobj.appendChild( elTr );

      var elTitleTd = document.createElement( 'td' );
      elTitleTd.innerHTML = books.author;
      elTr.appendChild( elTitleTd );

      var elDescriptionTd = document.createElement( 'td' );
      elDescriptionTd.innerHTML = books.title;
      elTr.appendChild( elDescriptionTd );
    }
  }

  function processReqChange()
  {
    if (req.readyState == 4 && req.status == 200 && req.responseText )
      eval( req.responseText );
  }
...

可以看到,processReqChange 函数中的代码现在转移到了 addData 中。

这组 XMLHttp 的用法可作为参考手册,帮助您在应用程序中使用 XMLHttp 对象处理不同的数据格式。
附件: 您所在的用户组无法下载或查看附件
一切皆有可能
七二个人博客 http://www.seven2.com.cn

TOP

发新话题