<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
<channel>
<title><![CDATA[PaulLeder--程序部落 - Ajax]]></title>
<link>http://bokee.shinylife.net/blog/</link>
<description><![CDATA[Be Your Personal Best]]></description>
<language>zh-cn</language>
<copyright><![CDATA[Copyright 2005 PBlog3 v2.8]]></copyright>
<webMaster><![CDATA[paulleder@msn.com(PaulLeder)]]></webMaster>
<generator>PBlog2 v2.4</generator> 
<image>
	<title>PaulLeder--程序部落</title>
	<url>http://bokee.shinylife.net/blog/images/logos.gif</url>
	<link>http://bokee.shinylife.net/blog/</link>
	<description>PaulLeder--程序部落</description>
</image>

			<item>
			<link>http://bokee.shinylife.net/blog/article.asp?id=658</link>
			<title><![CDATA[AJAX：如何处理书签和后退按钮]]></title>
			<author>paulleder@msn.com(PaulLeder)</author>
			<category><![CDATA[Ajax]]></category>
			<pubDate>Mon,24 Sep 2007 19:41:40 +0800</pubDate>
			<guid>http://bokee.shinylife.net/blog/default.asp?id=658</guid>
		<description><![CDATA[<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td height="64">时间：2006-05-26<br />作者：<a href="http://dev2dev.bea.com.cn/author/505.html">Brad Neuberg</a><br />浏览次数：
            <script language="JavaScript" src="/beadevcount.jsp?d_id=162286" type="text/JavaScript"></script>
            4113 <br />本文关键字：<a href="http://dev2dev.bea.com.cn/products/search.jsp?searchtype=keywords&amp;keywords=AJAX">AJAX</a>,&nbsp;<a href="http://dev2dev.bea.com.cn/products/search.jsp?searchtype=keywords&amp;keywords=javascript">javascript</a>,&nbsp;<a href="http://dev2dev.bea.com.cn/products/search.jsp?searchtype=keywords&amp;keywords=dom">dom</a>,&nbsp;<a href="http://dev2dev.bea.com.cn/products/search.jsp?searchtype=keywords&amp;keywords=bookmark">bookmark</a>,&nbsp;<a href="http://dev2dev.bea.com.cn/products/search.jsp?searchtype=keywords&amp;keywords=forward button">forward button</a>,&nbsp;<a href="http://dev2dev.bea.com.cn/products/search.jsp?searchtype=keywords&amp;keywords=back button">back button</a>,&nbsp;<a href="http://dev2dev.bea.com.cn/products/search.jsp?searchtype=keywords&amp;keywords=历史记录">历史记录</a>,&nbsp;<a href="http://dev2dev.bea.com.cn/products/search.jsp?searchtype=keywords&amp;keywords=书签">书签</a>,&nbsp;<a href="http://dev2dev.bea.com.cn/products/search.jsp?searchtype=keywords&amp;keywords=前进按钮">前进按钮</a>,&nbsp;<a href="http://dev2dev.bea.com.cn/products/search.jsp?searchtype=keywords&amp;keywords=后退按钮">后退按钮</a>,&nbsp;<a href="http://dev2dev.bea.com.cn/products/search.jsp?searchtype=keywords&amp;keywords=表示层">表示层</a></td>
        </tr>
    </tbody>
</table>
　本文将展示一个开源JavaScript库，该脚本库给<a href="http://en.wikipedia.org/wiki/AJAX" target="_blank">AJAX</a>应用程序带来了书签和后退按钮支持。在学习完这个教程后，开发人员将能够获得对一个AJAX问题的解决方案（甚至连<a href="http://maps.google.com/" target="_blank">Google Maps</a>和<a href="http://www.gmail.com/" target="_blank">Gmail</a>现在都不提供该解决方案）：一个强大的、可用的书签和后退前进功能，其操作行为如同其他的Web应用程序一样。
<p>　　本文将阐述目前AJAX应用程序在使用书签和后退按钮方面所面临的严重问题；展示Really Simple History（RSH）库&mdash;&mdash;一个可以解决以上问题的开源框架，并提供几个运行中的例子。</p>
<p>　　本文所展示的这个框架的主要发明分为两部分。首先是一个隐藏的HTML表单，用于缓存大量短期会话的客户端信息；这种缓存功能为页面导航提供了强大的支持。其次是超链接锚点和隐藏Iframe的组合，它们被嵌入后退和前进按钮，用来截获和记录浏览器的历史记录事件。以上两种技术都被包装在一个简单的JavaScript库中来简化开发。</p>
<h3>问题</h3>
<p>　　书签和后退按钮在传统的多页面Web应用程序中运行得非常好。当用户浏览web站点的时候，其浏览器的地址栏记录随新的URL而更新，这些记录可以被粘贴到电子邮件或者书签中供以后使用。后退和前进按钮也可以正常操作，使用户可以在访问过的页面中向前或向后翻动。</p>
<p>　　但是AJAX应用程序却不一样，它们是运行在单个Web页面中的复杂程序。浏览器并不是为这类程序而构建的&mdash;&mdash;这类Web应用程序已经过时，它们在每次鼠标点击的时候都需要重新刷新整个页面。</p>
<p>　　在这种类似于Gmail的AJAX软件中，浏览器的地址栏在用户选择功能和改变程序状态的时候保持不变，这使得无法在特定的应用程序视图中使用书签。此外，如果用户按下&ldquo;后退&rdquo;按钮来&ldquo;撤销&rdquo;上次的操作，他们会惊奇地发现，浏览器会完全离开该应用程序的Web页面。</p>
<h3>解决方案</h3>
<p>　　开源RSH框架可以解决这些问题，它为AJAX应用程序提供了书签和控制后退、前进按钮的功能。RSH目前还处于Beta阶段，可以在Firefox 1.0、Netscape 7+、Internet Explorer 6+等浏览器上运行；目前还不支持Safari（有关说明，请参见我的文章&ldquo;<a href="http://codinginparadise.org/weblog/2005/09/safari-no-dhtml-history-possible.html" target="_blank">Coding in Paradise: Safari: No DHTML History Possible</a>&rdquo;）。</p>
<p>　　目前有几个AJAX框架对书签和历史记录问题有所帮助；但这些框架目前都有几个由于实现而造成的重大Bug（有关详细信息，请参见&ldquo;<a href="http://codinginparadise.org/weblog/2005/09/ajax-history-libraries.html" target="_blank">Coding in Paradise: AJAX History Libraries</a>&rdquo;）。此外，很多AJAX历史记录框架被绑定到较大的库上，例如<a href="http://www.backbase.com/" target="_blank">Backbase</a>和<a href="http://www.dojotoolkit.org/" target="_blank">Dojo</a>；这些框架为AJAX应用程序引入了完全不同的编程模型，迫使开发人员使用全新的方式来获得历史记录功能。</p>
<p>　　相较之下，RSH是一个可以包含在现有AJAX系统中的简单模块。此外，RSH库采用了一些技术以避免产生影响其他历史记录框架的Bug。</p>
<p>　　RSH框架由两个JavaScript类组成：DhtmlHistory和HistoryStorage。</p>
<p>　　DhtmlHistory类为AJAX应用程序提供历史记录抽象。AJAX页面使用add()方法添加历史记录事件到浏览器，指定新的地址和相关的历史记录数据。DhtmlHistory类使用一个锚散列（如#new-location）更新浏览器当前的URL，同时把历史记录数据和该新URL关联。AJAX应用程序将自己注册为历史记录的监听器，当用户使用后退和前进按钮进行浏览时，历史记录事件被触发，为浏览器提供新的位置以及与add()调用一起保存的任何历史记录数据。</p>
<p>　　第二个类：HistoryStorage，允许开发人员保存任意数量的已存历史记录数据。在普通Web页面中，当用户导航到一个新的web站点时，浏览器卸载并清除web页面上的所有应用程序和JavaScript状态；如果用户用后退按钮返回，所有的数据都丢失了。HistoryStorage类通过一个包含简单散列表方法（例如put()、get()、hasKey()）的API来解决这类问题。上面的方法允许开发人员在用户离开Web页面之后保存任意数量的数据；当用户按后退按钮重新返回时，历史记录数据可以通过HistoryStorage类来访问。在内部，我们通过使用隐藏的表单字段来实现此功能，这是因为浏览器会自动保存表单字段中的值，甚至在用户离开Web页面的时候也如此。</p>
<h3>例子</h3>
<p>　　让我们先从一个简单的例子开始。</p>
<p>　　首先，任何需要使用RSH框架的页面都必须包含dhtmlHistory.js脚本：</p>
<pre class="code">&lt;!-- Load the Really Simple
History framework --&gt;
&lt;script type=&quot;text/javascript&quot;
src=&quot;../../framework/dhtmlHistory.js&quot;&gt;
&lt;/script&gt;</pre>
<p>　　DHTML历史记录应用程序也必须在与AJAX Web页面相同的目录下包含blank.html文件；这个文件与RSH框架<a href="http://codinginparadise.org/projects/dhtml_history/latest.zip" target="_blank">打包</a>在一起，且对于Internet Explorer来说是必需的。顺便提一下，RSH使用一个<a href="http://codinginparadise.org/weblog/2005/08/ajax-tutorial-tale-of-two-iframes-or.html" target="_blank">隐藏Iframe</a>来跟踪和添加Internet Explorer的历史记录变化；这个Iframe需要我们指定一个实际的文件位置才能正常工作，这就是blank.html。</p>
<p>　　RSH框架创建了一个叫做dhtmlHistory的全局对象，这是操纵浏览器历史记录的入口点。使用dhtmlHistory的第一步是在Web页面加载完成后初始化dhtmlHistory对象：</p>
<pre class="code">window.onload = initialize;
function initialize() {
// initialize the DHTML History
// framework
dhtmlHistory.initialize();
</pre>
<p>　　然后，开发人员使用dhtmlHistory.addListener()方法订阅历史记录变化事件。这个方法带有一个JavaScript回调函数，当DHTML历史记录变化事件发生时，该函数接收两个参数：新的页面位置以及任何可与该事件关联的可选历史记录数据：</p>
<pre class="code">window.onload = initialize;
function initialize() {
// initialize the DHTML History
// framework
dhtmlHistory.initialize();
// subscribe to DHTML history change
// events
dhtmlHistory.addListener(historyChange);
</pre>
<p>　　historyChange()方法很简单，该函数在用户导航到一个新位置后接收newLocation以及任何与该事件关联的可选historyData。</p>
<pre class="code">/** Our callback to receive history change
events. */
function historyChange(newLocation,
historyData) {
debug(&quot;A history change has occurred: &quot;
+ &quot;newLocation=&quot;+newLocation
+ &quot;, historyData=&quot;+historyData,
true);
}
</pre>
<p>　　上面用到的debug()方法是定义在示例源文件中的一个实用函数，它与完整示例<a href="http://www.onjava.com/onjava/2005/10/26/examples/downloads/examples.zip" target="_blank">打包</a>在一起供下载。debug()只是用来将消息打印到Web页面上；第二个布尔型参数（在上述代码中值为true）控制是否在打印新的调试消息之前清除原有的全部消息。</p>
<p>　　开发人员使用add()方法添加历史记录事件。添加历史记录事件涉及为历史记录变化指定一个新地址，例如edit:SomePage，以及提供一个和该事件一起保存的可选historyData值。</p>
<pre class="code">window.onload = initialize;
function initialize() {
// initialize the DHTML History
// framework
dhtmlHistory.initialize();
// subscribe to DHTML history change
// events
dhtmlHistory.addListener(historyChange);
// if this is the first time we have
// loaded the page...
if (dhtmlHistory.isFirstLoad()) {
debug(&quot;Adding values to browser &quot;
+ &quot;history&quot;, false);
// start adding history
dhtmlHistory.add(&quot;helloworld&quot;,
&quot;Hello World Data&quot;);
dhtmlHistory.add(&quot;foobar&quot;, 33);
dhtmlHistory.add(&quot;boobah&quot;, true);
var complexObject = new Object();
complexObject.value1 =
&quot;This is the first value&quot;;
complexObject.value2 =
&quot;This is the second data&quot;;
complexObject.value3 = new Array();
complexObject.value3[0] = &quot;array 1&quot;;
complexObject.value3[1] = &quot;array 2&quot;;
dhtmlHistory.add(&quot;complexObject&quot;,
complexObject);
</pre>
<p>　　在add()被调用之后，新的地址将立即作为一个锚值（链接地址）显示在浏览器的URL地址栏中。例如，对地址为http://codinginparadise.org/my_ajax_app的AJAX Web页面调用dhtmlHistory.add(&quot;helloworld&quot;, &quot;Hello World Data&quot;)之后，用户将会在其浏览器URL地址栏中看到如下的地址：</p>
<pre>http://codinginparadise.org/my_ajax_app#helloworld </pre>
<p>　　然后用户可以将这个页面做成书签，如果以后用到这个书签，AJAX应用程序可以读取#helloworld值，并用它来初始化Web页面。散列后面的地址值是RSH框架可以透明编码和解码的URL地址。</p>
<p>　　HistoryData非常有用，它保存比简单的URL更为复杂的AJAX地址变化状态。这是一个可选值，可以是任何JavaScript类型，例如Number、String或Object。使用该保存功能的一个例子是在一个富文本编辑器中保存所有文本（比如在用户离开当前页面时）。当用户再回到这个地址时，浏览器将会将该对象返回给历史记录变化监听器。</p>
<p>　　开发人员可以为historyData提供带有嵌套对象和表示复杂状态的数组的完整JavaScript对象；<a href="http://www.crockford.com/JSON/index.html" target="_blank">JSON (JavaScript Object Notation)</a>所支持的在历史记录数据中都支持，包括简单数据类型和null类型。然而，DOM对象以及可用脚本编写的浏览器对象（如XMLHttpRequest）不会被保存。请注意，historyData并不随书签一起保存，当浏览器关闭，浏览器缓存被清空，或者用户清除历史记录的时候，它就会消失。</p>
<p>　　使用dhtmlHistory的最后一步是isFirstLoad()方法。在某些浏览器中，如果导航到一个Web页面，再跳转到另一个不同的页面，然后按&ldquo;后退&rdquo;按钮返回到起始的站点，第一页将完全重新加载，并触发onload事件。这样会对想要在第一次加载页面时用某种方式对其进行初始化（而其后则不使用这种方式重新加载该页面）的代码造成破坏。isFirstLoad()方法可以区分是第一次加载一个Web页面还是用户导航到保存在历史记录中的Web页面时触发的&ldquo;假加载&rdquo;事件。</p>
<p>　　在示例代码中，我们只想在第一次加载页面的时候添加历史记录事件；如果用户在加载页面后按后退按钮返回该页面，我们就不想重新添加任何历史记录事件：</p>
<pre class="code">window.onload = initialize;
function initialize() {
// initialize the DHTML History
// framework
dhtmlHistory.initialize();
// subscribe to DHTML history change
// events
dhtmlHistory.addListener(historyChange);
// if this is the first time we have
// loaded the page...
if (dhtmlHistory.isFirstLoad()) {
debug(&quot;Adding values to browser &quot;
+ &quot;history&quot;, false);
// start adding history
dhtmlHistory.add(&quot;helloworld&quot;,
&quot;Hello World Data&quot;);
dhtmlHistory.add(&quot;foobar&quot;, 33);
dhtmlHistory.add(&quot;boobah&quot;, true);
var complexObject = new Object();
complexObject.value1 =
&quot;This is the first value&quot;;
complexObject.value2 =
&quot;This is the second data&quot;;
complexObject.value3 = new Array();
complexObject.value3[0] = &quot;array 1&quot;;
complexObject.value3[1] = &quot;array 2&quot;;
dhtmlHistory.add(&quot;complexObject&quot;,
complexObject);
</pre>
<p>　　让我们继续使用historyStorage类。类似于dhtmlHistory，historyStorage通过一个叫historyStorage的全局对象来公开它的功能。该对象有几个模拟散列的方法，比如put(keyName、keyValue)、get(keyName)和hasKey(keyName)。键名称必须是字符串，同时键值可以是复杂的JavaScript对象甚至是XML格式的字符串。在我们的源代码例子中，在第一次加载页面时，我们使用put()将简单的XML放入historyStorage：</p>
<pre class="code">window.onload = initialize;
function initialize() {
// initialize the DHTML History
// framework
dhtmlHistory.initialize();
// subscribe to DHTML history change
// events
dhtmlHistory.addListener(historyChange);
// if this is the first time we have
// loaded the page...
if (dhtmlHistory.isFirstLoad()) {
debug(&quot;Adding values to browser &quot;
+ &quot;history&quot;, false);
// start adding history
dhtmlHistory.add(&quot;helloworld&quot;,
&quot;Hello World Data&quot;);
dhtmlHistory.add(&quot;foobar&quot;, 33);
dhtmlHistory.add(&quot;boobah&quot;, true);
var complexObject = new Object();
complexObject.value1 =
&quot;This is the first value&quot;;
complexObject.value2 =
&quot;This is the second data&quot;;
complexObject.value3 = new Array();
complexObject.value3[0] = &quot;array 1&quot;;
complexObject.value3[1] = &quot;array 2&quot;;
dhtmlHistory.add(&quot;complexObject&quot;,
complexObject);
// cache some values in the history
// storage
debug(&quot;Storing key 'fakeXML' into &quot;
+ &quot;history storage&quot;, false);
var fakeXML =
'&lt;?xml version=&quot;1.0&quot; '
+      'encoding=&quot;ISO-8859-1&quot;?&gt;'
+      '&lt;foobar&gt;'
+         '&lt;foo-entry/&gt;'
+      '&lt;/foobar&gt;';
historyStorage.put(&quot;fakeXML&quot;, fakeXML);
} </pre>
<p>　　然后，如果用户离开页面后又通过后退按钮返回该页面，我们可以使用get()方法提取保存的值，或者使用hasKey()方法检查该值是否存在。</p>
<pre class="code">window.onload = initialize;
function initialize() {
// initialize the DHTML History
// framework
dhtmlHistory.initialize();
// subscribe to DHTML history change
// events
dhtmlHistory.addListener(historyChange);
// if this is the first time we have
// loaded the page...
if (dhtmlHistory.isFirstLoad()) {
debug(&quot;Adding values to browser &quot;
+ &quot;history&quot;, false);
// start adding history
dhtmlHistory.add(&quot;helloworld&quot;,
&quot;Hello World Data&quot;);
dhtmlHistory.add(&quot;foobar&quot;, 33);
dhtmlHistory.add(&quot;boobah&quot;, true);
var complexObject = new Object();
complexObject.value1 =
&quot;This is the first value&quot;;
complexObject.value2 =
&quot;This is the second data&quot;;
complexObject.value3 = new Array();
complexObject.value3[0] = &quot;array 1&quot;;
complexObject.value3[1] = &quot;array 2&quot;;
dhtmlHistory.add(&quot;complexObject&quot;,
complexObject);
// cache some values in the history
// storage
debug(&quot;Storing key 'fakeXML' into &quot;
+ &quot;history storage&quot;, false);
var fakeXML =
'&lt;?xml version=&quot;1.0&quot; '
+      'encoding=&quot;ISO-8859-1&quot;?&gt;'
+      '&lt;foobar&gt;'
+         '&lt;foo-entry/&gt;'
+      '&lt;/foobar&gt;';
historyStorage.put(&quot;fakeXML&quot;, fakeXML);
}
// retrieve our values from the history
// storage
var savedXML =
historyStorage.get(&quot;fakeXML&quot;);
savedXML = prettyPrintXml(savedXML);
var hasKey =
historyStorage.hasKey(&quot;fakeXML&quot;);
var message =
&quot;historyStorage.hasKey('fakeXML')=&quot;
+ hasKey + &quot;&lt;br&gt;&quot;
+ &quot;historyStorage.get('fakeXML')=&lt;br&gt;&quot;
+ savedXML;
debug(message, false);
}</pre>
<p>　　prettyPrintXml()是一个定义在<a href="http://www.onjava.com/onjava/2005/10/26/examples/downloads/examples.zip" target="_blank">完整示例源代码</a>中的实用方法；此函数准备在web页面中显示以便用于调试的简单XML。</p>
<p>　　请注意，相关数据只在该页面的历史记录中进行持久化；如果浏览器被关闭，或者用户打开一个新窗口并再次键入AJAX应用程序的地址，则该历史记录数据对于新的Web页面不可用。历史记录数据只有在用到后退或前进按钮时才被持久化，当用户关闭浏览器或清空缓存的时候就会消失。如果想真正长期持久化，请参阅<a href="http://codinginparadise.org/projects/storage/README.html" target="_blank">Ajax MAssive Storage System (AMASS)</a>。</p>
<p>　　我们的简单示例已经完成。您可以<a href="http://www.onjava.com/onjava/2005/10/26/examples/examples/simple/simple.html">演示</a>或<a href="http://www.onjava.com/onjava/2005/10/26/examples/downloads/examples.zip">下载完整源代码</a>。</p>
<h3>示例2：O'Reilly Mail</h3>
<p>　　我们的第二个例子是一个简单的AJAX电子邮件模拟应用程序的示例，即O'Reilly Mail，它类似于Gmail。O'Reilly Mail描述了如何使用dhtmlHistory类来控制浏览器的历史记录，以及如何使用historyStorage对象来缓存历史记录数据。</p>
<p>　　O'Reilly Mail用户界面由两部分组成。在页面的左边是一个带有不同电子邮件文件夹和选项的菜单，例如收件箱、草稿箱等。当用户选择了一个菜单项（如收件箱），就用这个菜单项的内容更新右边的页面。在一个现实应用程序中，我们会远程获取并显示选择的信箱内容，不过在O'Reilly Mail中，我们只显示已选择的选项。</p>
<p>　　O'Reilly Mail使用RSH框架向浏览器历史记录中添加菜单变化并更新地址栏，允许用户利用浏览器的后退和前进按钮为应用程序做收藏书签和跳到上次变化的菜单。</p>
<p>　　我们添加一个特殊的菜单项&mdash;&mdash;地址簿，以说明如何来使用historyStorage。地址簿是一个由联系人名称和邮件地址组成的JavaScript数组，在一个现实应用程序中，我们会从一台远程服务器取得这个数组。不过，在O'Reilly Mail中，我们在本地创建这个数组，添加几个名称和电子邮件地址，然后将其保存在historyStorage对象中。如果用户离开Web页面后又返回该页面，那么O'Reilly Mail应用程序将重新从缓存检索地址簿，而不是再次联系远程服务器。</p>
<p>　　我们用initialize()方法保存和检索地址簿：</p>
<pre class="code">/** Our function that initializes when the page
is finished loading. */
function initialize() {
// initialize the DHTML History framework
dhtmlHistory.initialize();
// add ourselves as a DHTML History listener
dhtmlHistory.addListener(handleHistoryChange);
// if we haven't retrieved the address book
// yet, grab it and then cache it into our
// history storage
if (window.addressBook == undefined) {
// Store the address book as a global
// object.
// In a real application we would remotely
// fetch this from a server in the
// background.
window.addressBook =
[&quot;Brad Neuberg 'bkn3@columbia.edu'&quot;,
&quot;John Doe 'johndoe@example.com'&quot;,
&quot;Deanna Neuberg 'mom@mom.com'&quot;];
// cache the address book so it exists
// even if the user leaves the page and
// then returns with the back button
historyStorage.put(&quot;addressBook&quot;,
addressBook);
}
else {
// fetch the cached address book from
// the history storage
window.addressBook =
historyStorage.get(&quot;addressBook&quot;);
}
</pre>
<p>　　处理历史记录变化的代码也很简单。在下面的源代码中，无论用户按后退还是前进按钮，都将调用handleHistoryChange。使用O'Reilly Mail定义的displayLocation实用方法，我们可得到newLocation并使用它将我们的用户界面更新到正确的状态。</p>
<pre class="code">/** Handles history change events. */
function handleHistoryChange(newLocation,
historyData) {
// if there is no location then display
// the default, which is the inbox
if (newLocation == &quot;&quot;) {
newLocation = &quot;section:inbox&quot;;
}
// extract the section to display from
// the location change; newLocation will
// begin with the word &quot;section:&quot;
newLocation =
newLocation.replace(/section\:/, &quot;&quot;);
// update the browser to respond to this
// DHTML history change
displayLocation(newLocation, historyData);
}
/** Displays the given location in the
right-hand side content area. */
function displayLocation(newLocation,
sectionData) {
// get the menu element that was selected
var selectedElement =
document.getElementById(newLocation);
// clear out the old selected menu item
var menu = document.getElementById(&quot;menu&quot;);
for (var i = 0; i &lt; menu.childNodes.length;
i++) {
var currentElement = menu.childNodes[i];
// see if this is a DOM Element node
if (currentElement.nodeType == 1) {
// clear any class name
currentElement.className = &quot;&quot;;
}
}
// cause the new selected menu item to
// appear differently in the UI
selectedElement.className = &quot;selected&quot;;
// display the new section in the right-hand
// side of the screen; determine what
// our sectionData is
// display the address book differently by
// using our local address data we cached
// earlier
if (newLocation == &quot;addressbook&quot;) {
// format and display the address book
sectionData = &quot;&lt;p&gt;Your addressbook:&lt;/p&gt;&quot;;
sectionData += &quot;&lt;ul&gt;&quot;;
// fetch the address book from the cache
// if we don't have it yet
if (window.addressBook == undefined) {
window.addressBook =
historyStorage.get(&quot;addressBook&quot;);
}
// format the address book for display
for (var i = 0;
i &lt; window.addressBook.length;
i++) {
sectionData += &quot;&lt;li&gt;&quot;
+ window.addressBook[i]
+ &quot;&lt;/li&gt;&quot;;
}
sectionData += &quot;&lt;/ul&gt;&quot;;
}
// If there is no sectionData, then
// remotely retrieve it; in this example
// we use fake data for everything but the
// address book
if (sectionData == null) {
// in a real application we would remotely
// fetch this section's content
sectionData = &quot;&lt;p&gt;This is section: &quot;
+ selectedElement.innerHTML + &quot;&lt;/p&gt;&quot;;
}
// update the content's title and main text
var contentTitle =
document.getElementById(&quot;content-title&quot;);
var contentValue =
document.getElementById(&quot;content-value&quot;);
contentTitle.innerHTML =
selectedElement.innerHTML;
contentValue.innerHTML = sectionData;
}</pre>
<p>　　您可以<a href="http://www.onjava.com/onjava/2005/10/26/examples/examples/oreillymail/oreillymail.html" target="_blank">演示</a>O'Reilly Mail或者<a href="http://www.onjava.com/onjava/2005/10/26/examples/downloads/examples.zip" target="_blank">下载</a>O'Reilly Mail源代码。</p>
<h3>结束语</h3>
<p>　　现在我们已经了解了如何使用RSH API来使AJAX应用程序支持书签以及后退和前进按钮，并提供了示例代码，您可参考该示例来创建自己的应用程序。希望您能利用书签和历史记录的支持来增强AJAX应用程序。</p>
<h3>参考资料</h3>
<ul type="disc">
    <li><a href="http://www.onjava.com/onjava/2005/10/26/examples/downloads/examples.zip" target="_blank">下载</a>此文的所有示例代码。 </li>
    <li><a href="http://codinginparadise.org/projects/dhtml_history/latest.zip" target="_blank">下载</a>RSH框架。 </li>
    <li><a href="http://www.onjava.com/onjava/2005/10/26/examples/examples/oreillymail/oreillymail.html" target="_blank">演示</a>O'Reilly Mail或者<a href="http://www.onjava.com/onjava/2005/10/26/examples/downloads/examples.zip" target="_blank">下载</a>O'Reilly Mail源代码。完整的示例下载还包括更多供试用的示例。 </li>
    <li><a href="http://codinginparadise.org/" target="_blank">Coding in Paradise</a>：作者的weblog，内容涵盖了AJAX、DHTML以及Java技术和利用协作技术的新开发，例如WikiWikis。 </li>
    <li><a href="http://codinginparadise.org/weblog/2005/09/ajax-how-to-handle-bookmarks-and-back.html" target="_blank">&quot;Coding in Paradise: AJAX: Bookmarks and Back Buttons, Advanced Example&quot;</a> </li>
    <li><a href="http://codinginparadise.org/weblog/2005/09/safari-no-dhtml-history-possible.html" target="_blank">&quot;Coding in Paradise: Safari: No DHTML History Possible&quot;</a> </li>
    <li><a href="http://codinginparadise.org/weblog/2005/08/ajax-tutorial-saving-session-across.html" target="_blank">&quot;Coding in Paradise: AJAX Tutorial: Saving Session Across Page Loads Without Cookies, On The Client Side&quot;</a> </li>
    <li><a href="http://codinginparadise.org/weblog/2005/09/ajax-history-libraries.html" target="_blank">&quot;Coding in Paradise: AJAX History Libraries&quot;</a> </li>
</ul>
<p><b>原文出处:</b><a href="http://www.onjava.com/pub/a/onjava/2005/10/26/ajax-handling-bookmarks-and-back-button.html" target="_blank">http://www.onjava.com/pub/a/onjava/2005/10/26/ajax-handling-bookmarks-and-back-button.html</a></p>
<!--文章其他信息-->]]></description>
		</item>
		
			<item>
			<link>http://bokee.shinylife.net/blog/article.asp?id=599</link>
			<title><![CDATA[ajax处理数据乱码问题终极解决办法]]></title>
			<author>paulleder@msn.com(PaulLeder)</author>
			<category><![CDATA[Ajax]]></category>
			<pubDate>Tue,14 Aug 2007 21:18:01 +0800</pubDate>
			<guid>http://bokee.shinylife.net/blog/default.asp?id=599</guid>
		<description><![CDATA[也许用这个标题有点大，但是真的有效。<br/>解决办法还是源于ajax处理时默认的字符集是utf-8<br/>那么我们只需要把需要调用的页面（或是数据处理页面）保存成utf-8格式即可。<br/><br/>说标题有点大，是因为这样可能会带来一个问题就是：网站的默认字符集不是utf-8的页面变成乱码，此问题还在考究中。。。<br/><br/>另如果调用的页面是js的话完全可以使用这个方法。<br/><br/>（js调用有一个charset可以控制字符集合，就是说如果被调用的js还需要潜入web里可以这样写<br/>&lt;script type=&#34;text/javascript&#34; charset=&#34;utf-8&#34; src=&#34;&#34;&gt;&lt;/script&gt;<br/>）]]></description>
		</item>
		
			<item>
			<link>http://bokee.shinylife.net/blog/article.asp?id=583</link>
			<title><![CDATA[Web2.0十大Ajax安全漏洞以及成因]]></title>
			<author>paulleder@msn.com(PaulLeder)</author>
			<category><![CDATA[Ajax]]></category>
			<pubDate>Thu,26 Jul 2007 20:38:20 +0800</pubDate>
			<guid>http://bokee.shinylife.net/blog/default.asp?id=583</guid>
		<description><![CDATA[&#34;&gt;Ajax中没有固有的安全漏洞，但是对该技术向量的适配显著地改变了网络应用的开发途径以及方法论。以前，DCOM和CORBA组成核心中间件层的时候，将数据和对象序列化非常困难。Ajax使用简单的GET,POST或者SOAP调用，来转换XML,HTML,JS Array,JSON,JS Objects以及其他定制的对象；全部这些操作都不需要调用中间件层。Ajax的这种综合能力使应用服务器与浏览器之间的数据交换非常流畅。从服务器端传来的信息动态地被注入到当前的DOM相关环境，然后浏览器的DOM状态重置。在讲安全漏洞之前，我们先来看看促成Web2.0漏洞的关键因素。 <br/><br/>多重分散的终端点以及隐藏调用——Web2.0应用与Web1.0的主要区别就是信息访问机制的区别。比起它的前身Web1.0, Web2.0应用有数个Ajax终点。潜在的Ajax调用分散于整个浏览器页面，并且能够被各个事件分别调用。开发者恨难应付Ajax调用的这种分散性，并且由于这些调用是隐藏的，不那么明显，它还可能导致代码不规范。 <br/><br/>认证混乱——输入和输出内容认证是应用的重要因素之一。Web2.0应用使用桥，mashups,还有反馈等等。很多情况下，它假定“另一方”（读取服务器端或者客户端代码）已经实现了认证，这种混乱就导致了双方都没有实现适当的认证控制。 <br/><br/>不受信任的信息来源——Web2.0应用从很多不受信任的来源比如反馈，博客，搜索结果中获得信息。这些内容在提供给终端浏览器之前从来没有被认证，这就有可能引发跨站点攻击。黑客还有可能在浏览器中加载&#34;&gt;数据序列化——浏览器可以调用Ajax来实施数据序列化。它可以获取JS array,Objects,Feeds,XML文件，HTML 块以及JSON。如果这些序列块中的某一个被解析并修改了，黑客们就可以强迫浏览器执行恶意脚本。不受信任信息与数据序列化的结合，对终端用户的安全是致命的。 <br/><br/>动态脚本构成和执行——Ajax会建立一个后端通道，从服务器获取数据，然后将它传送给DOM。实现这一点的必要条件就是动态地执行&#34;&gt;Web2.0应用可能因为上面提到的1个或多个失误而变得易受攻击。如果开发者不够审慎，没有花心思在安全管理上的话，那么服务器和浏览器端都会出现安全问题。以下是10个可能的安全漏洞的简要说明。 <br/><br/>（1）畸形的JS对象序列 <br/><br/>&#34;&gt;message = {<br/><br/>from : &#34;john@example.com&#34;,<br/><br/>to : &#34;jerry@victim.com&#34;,<br/><br/>subject : &#34;I am fine&#34;,<br/><br/>body : &#34;Long message here&#34;,<br/><br/>showsubject : function(){document.write(this.subject)}<br/><br/>};<br/><br/>这是一个简单的消息对象，其中有2个字段需要电子邮件地址。我们可以使用Ajax来将该对象序列化并用&#34;&gt;(2)JSON对注入 <br/><br/>&#34;Link&#34;:&#34;www.example.com&#34;,&#34;Desc&#34;:&#34;Interesting link&#34;}]}<br/><br/>黑客们可以在Link或者Desc中注入恶意脚本。如果DOM和可执行程序被注入了，XSS目录也会被注入。这是使终端用户感染恶意内容的另一种方法。 <br/><br/>(3)JS数组中毒 <br/><br/>JS数组是另一个比较普遍的序列化对象。人们可以很容易地跨平台移植它，并且它在使用不同语言的结构中也很有效。感染一个JS数组可以扰乱整个DOM环境。黑客们可以在浏览器中使用简单的跨站点脚本攻击JS数组。下面是一个JS数组的例子： <br/><br/>new Array(“Laptop”, “Thinkpad”, “T60”, “Used”, “900$”, “It <br/><br/>is great and I have used it for 2 years”)<br/><br/>该数组是从一个拍卖二手笔记本的网站传出来的。如果这个数组对象在服务器端没有被仔细处理，黑客就可以在最后字段中注入脚本。这种注入将危及浏览器安全并被攻击者利用。 <br/><br/>(4)被修改的XML数据流 <br/><br/>Ajax调用接受来自多个地址的XML。这些XML块来自运行在SOAP,REST或者XML-RPC的网络服务。这些网络服务是由从第三方的代理桥那里接收过来的。如果这些第三方XML数据流被攻击者修改过，那么攻击者就可能向其中注入恶意内容。 <br/><br/>浏览器从它自带的XML解析器接收该数据流。该解析器容易受不同的XML炸弹的攻击。人们也可以在该数据流中注入脚本，这样就可以导致跨站点脚本攻击(XSS)。浏览器接收未经认证的XML数据流的话，这就会危及终端客户端的安全。 <br/><br/>(5)DOM中脚本注入 <br/><br/>前四个漏洞都是由于序列化问题引起的。一旦浏览器收到序列化的对象数据流，开发者会发出某种调用来访问DOM。这种调用的目的是将新内容“重写”或者“重填”入DOM中，可以调用eval()这个定制功能，也可以使用document.write()。如果这些调用是在不受信任信息流上进行的，浏览器就有可能由于DOM的操作漏洞而受攻击。攻击者可以用很多document.*()调用来向DOM环境中注入XSS。 <br/><br/>例如，这段&#34;&gt;在这里，“Product-review”是从第三方blog上获得的变量。如果它含有&#34;&gt;Ajax不能从浏览器跨域访问。所有比较流行的浏览器都有个安全特性，那就是拦截跨域访问。一些网站服务为对象序列提供回调功能。开发者可以使用这个功能来把网站服务整合到浏览器本身。人们可以把该功能名传回，这样浏览器一找到回调对象数据流，它就会被浏览器中早已有的特殊功能名执行。 <br/><br/>这个回调对使用浏览器内认证的开发者来说是个额外负担。如果输入的对象数据流未经浏览器认证那么终端客户端就会成为跨域攻击的目标。不管是有意还是无意的，跨域服务可以向浏览器中注入恶意内容。该跨域调用在当前DOM环境中运行，于是导致当前对话也易受攻击。在实现应用之前，人们需要仔细检查整个跨域功能。 <br/><br/>（7）RSS和Atom注入 <br/><br/>联合的反馈，RSS以及Atom,是最普遍的一种将站点更新信息传到网络上的方法。许多新闻，博客，门户站点等等，都在网络上共享多个反馈。反馈是标准的XML文档，并且可以被任何程序接收。Web2.0应用使用窗口小部件或者浏览器内部元件整合了联合反馈。这些组件调用Ajax来访问反馈。 <br/><br/>这些反馈可以被终端用户方便地选择。一旦用户选择了它们，这些反馈就会被解析并注入到DOM中。那么如果这个反馈在注入之前没有被适当地认证过，就会出现一些安全问题。人们可以往浏览器中注入恶意链接或者&#34;&gt;（8）单击炸弹 <br/><br/>Web2.0应用可能不会很简单地就被黑客攻下，但他们可以对它进行基于事件的注入。人们可以将带有&#34;onclick&#34;字样的恶意链接用&#34;&gt;这也是由于人们从那些没有经过正确验证的不受信任源处获得的信息，所导致的安全漏洞。为了利用该安全漏洞，它需要终端客户端触发一个事件。这个事件也许是诸如点击按钮或者链接的这种无害事件，但是点击后就使会用户损失惨重。它可能引起某个恶意事件，将当前对话信息发送给目标，又或者在当前浏览器环境中执行一系列脚本攻击。 <br/><br/>(9) 基于Flash的跨域访问 <br/><br/>黑客们可以使用Flash插件的Ajax接口，从而用浏览器中的JavaScritps发出GET和POST请求。这个接口使黑客们能进行跨域调用。为了避免安全问题，该Flash插件实现了根据策略访问其他域的功能。该策略可以通过在域的根部放置crossdomain.xml文件来配置。如果放置的文件配置不当——很普遍的现象——它就可能允许跨域访问。下面是一个配置不当的XML文档： <br/><br/>现在可以从浏览器自身发出跨域调用了。这个结构还有一些其他安全问题。基于Flash的丰富网络应用(RIA)如果配置错误的话，很容易由于Ajax的跨域访问Bug而被攻击。 <br/><br/>(10) XSRF <br/><br/>跨域伪造请求(XSRF)是个老牌的攻击向量了，它迫使浏览器向不同的域发出HTTP GET或者POST请求；这些请求可以跨域在运行的应用逻辑中启动某种事件。它可能请求修改密码或者电子邮件地址等。浏览器调用它后，它重放cookie并获得身份认证。这就是该请求的关键部分。如果某个应用只根据cookie来判识身份，那么该攻击就会成功。 <br/><br/>Web2.0中Ajax是就XML-RPC,SOAP或者REST与后端网络服务进行对话的，通过GET和POST可以进行这些调用。换句话说，人们可以对这些网络服务进行跨站点调用，从而危及受害者与网络服务接口的身份信息。XSRF这个攻击向量很有趣，它在这个新界定的端点情况中创造了新的层次。这些终点可能是为Ajax或者网络服务而准备的，但它们也有可能被跨域请求所激活。 <br/><br/>对安全漏洞的攻击以及相应对策 <br/><br/>Web2.0应用有多个终端点；每个点都是威胁的侵入点。为了保证安全，我们应当保护好所有这些点。在将第三方信息发送给客户端之前要对其进行彻底处理。 <br/><br/>为了处理Ajax序列，必须在它们到达DOM之前对输入数据流进行验证。XML解析以及跨域安全问题也需要额外重视，并实施更好的安全管理措施。我们应当遵循那个最简单最笨拙的原则：不让未经认证的跨域信息进入浏览器。有趣的是，到目前为止，安全专家们都不主张使用客户端脚本来进行输入验证，因为这很容易被规避掉。 <br/><br/>Web2.0促成了很多浏览器安全相关的新的漏洞。利用这些安全漏洞很难但不是不可能。安全问题以及促成因素结合起来将严重影响那些大的网络团体，比如能被攻击者蠕虫和病毒利用的那些组织。最终将导致身份信息的泄漏。 <br/><br/>结论 <br/><br/>本文简单地讲了一些可能出现的关于Ajax漏洞。还有很多其他潜在的漏洞，比如利用跨域代理来在浏览器中建立单项通道或者存储变量。 <br/><br/>Web2.0中很多逻辑都转到了客户端。这会将整个应用暴露给一些严重的威胁。对整合来自多方的、不受信源的数据的迫切要求也将全面增加风险向量：XSS,XSRF,跨域问题以及客户端上的序列，还有不安全的网站服务，服务器端的XML-RPC和REST访问。相反地，Ajax可被用来构造优美的无缝数据整合。但是，任一不安全的调用或者信息流都会使其产事与愿违的效果，从而促成可被利用的安全漏洞。 <br/><br/>这些新技术向量很有前景，令很多人兴奋不已，但是攻击者，病毒和蠕虫作者对它更感兴趣。为了保障安全，开发者应当在这些细节方面格外小心。 <br/><br/>作者：杜莉 Shreeraj Shah 　　　来源：赛迪网 <br/>]]></description>
		</item>
		
			<item>
			<link>http://bokee.shinylife.net/blog/article.asp?id=582</link>
			<title><![CDATA[Ajax资源（摘自蓝色理想）]]></title>
			<author>paulleder@msn.com(PaulLeder)</author>
			<category><![CDATA[Ajax]]></category>
			<pubDate>Thu,26 Jul 2007 20:37:38 +0800</pubDate>
			<guid>http://bokee.shinylife.net/blog/default.asp?id=582</guid>
		<description><![CDATA[一.资源类网站<br/><br/>1,国内网站<br/>1)Ajax中国(推荐)<br/>一个专业的ajax技术网站,分类清晰,有大量的电子版教程,以及AJAX源码下载!<br/><a href="http://www.okajax.com" target="_blank" rel="external">http://www.okajax.com</a><br/><br/>2)ajaxcn.org<br/>李琨老师的blog。李琨:《ajax实战》译者.<br/><a href="http://www.ajaxcn.org" target="_blank" rel="external">http://www.ajaxcn.org</a><br/>-----------------------------------------<br/>2,国外网站<br/>1)、Ajax 的诞生 <br/>Ajax: A New Approach to Web Applications <br/><a href="http://www.adaptivepath.com/publications/essays/archives/000385.php" target="_blank" rel="external"><a href="http://www.adaptivepath.com/publ" target="_blank" rel="external">http://www.adaptivepath.com/publ</a>ications/essays/archives/000385.php</a><br/><br/>2)、AJAX Matters <br/><a href="http://www.ajaxmatters.com" target="_blank" rel="external">http://www.ajaxmatters.com</a> <br/>关于 Ajax 技术一个信息量非常大的网站，有点像 Ajax 世界中的 TSS。 <br/><br/>3)、AJAX Patterns <br/>与 AJAX 设计模式相关的资源。 <br/><a href="http://www.ajaxpatterns.org" target="_blank" rel="external">http://www.ajaxpatterns.org</a> <br/><a href="http://www.softwareas.com/ajax-patterns" target="_blank" rel="external"><a href="http://www.softwareas.com/ajax-patterns" target="_blank" rel="external">http://www.softwareas.com/ajax-patterns</a></a> <br/><br/>4)、<a href="http://www.ajaxian.com" target="_blank" rel="external">http://www.ajaxian.com</a> <br/><br/>--------------------------------------------------------------------------------<br/><br/>二.热门文章<br/><br/>1.什么是AJAX<br/><a href="http://www.okajax.com" target="_blank" rel="external">http://www.okajax.com</a>/info/net/20060510.html<br/>2.ajax技术简介<br/><a href="http://www.okajax.com" target="_blank" rel="external">http://www.okajax.com</a>/info/basic/200604654.html<br/>3.ajax.net<br/><a href="http://www.okajax.com" target="_blank" rel="external">http://www.okajax.com</a>/info/basic/200604556.html<br/><a href="http://www.okajax.com" target="_blank" rel="external">http://www.okajax.com</a>/info/tech/200605589.html<br/><a href="http://weblogs.asp.net/mschwarz/archive/2005/04/11/399893.aspx" target="_blank" rel="external">http://weblogs.asp.net/mschwarz/archive/2005/04/11/399893.aspx</a>(英文)<br/><br/>--------------------------------------------------------------------------------<br/><br/>三.ajax相关下载（电子书教程/源码）<br/>1.Ajax基础教程电子版<br/><a href="http://www.okajax.com" target="_blank" rel="external">http://www.okajax.com</a>/info/bookdown/200604950.htm <br/>2.《AJAX实战》ajax in action电子版<br/><a href="http://www.okajax.com" target="_blank" rel="external">http://www.okajax.com</a>/info/bookdown/200604366.htm<br/>3.AJAX开发简略<br/><a href="http://www.okajax.com" target="_blank" rel="external">http://www.okajax.com</a>/info/bookdown/20060538.htm<br/>----------------------------<br/>4.AJAX版CD管理系统 (jsp)<br/><a href="http://www.okajax.com" target="_blank" rel="external">http://www.okajax.com</a>/info/codedown/200604327.htm<br/>5.Alexa 查询系统 (Xmlhttp + Ajax)<br/><a href="http://www.okajax.com" target="_blank" rel="external">http://www.okajax.com</a>/info/codedown/200604982.htm<br/>6.ASP.NET+AJAX解决网页打开等待问题<br/><a href="http://www.okajax.com" target="_blank" rel="external">http://www.okajax.com</a>/info/codedown/200604166.htm<br/>7.Ajax技术简介 (ajax demo)<br/><a href="http://www.okajax.com" target="_blank" rel="external">http://www.okajax.com</a>/info/codedown/200604576.htm<br/><br/>--------------------------------------------------------------------------------<br/><br/>四.ajax相关图书<br/>1.《Ajax实战》(目前Ajax领域最为全面深入的一本著作) <br/><a href="http://www.china-pub.com/computers/common/info.asp?id=28433" target="_blank" rel="external">http://www.china-pub.com/computers/common/info.asp?id=28433</a><br/>2.《Ajax基础教程》（亚马逊计算机榜首图书，国内第1本Ajax图书）<br/><a href="http://www.china-pub.com/computers/common/info.asp?id=28432" target="_blank" rel="external">http://www.china-pub.com/computers/common/info.asp?id=28432</a><br/>3.《Ajax 修炼之道-Web 2.0 入门》（Ajax从小工到专家的首选图书）<br/><a href="http://www.china-pub.com/computers/common/info.asp?id=29430" target="_blank" rel="external">http://www.china-pub.com/computers/common/info.asp?id=29430</a><br/>4.《征服Ajax+Lucene构建搜索引擎》<br/><a href="http://www.china-pub.com/computers/common/info.asp?id=29996" target="_blank" rel="external">http://www.china-pub.com/computers/common/info.asp?id=29996</a><br/>5.《征服Ajax--Web 2.0快速入门与项目实践（.net）》<br/><a href="http://www.china-pub.com/computers/common/info.asp?id=29995" target="_blank" rel="external">http://www.china-pub.com/computers/common/info.asp?id=29995</a><br/>6.《Ajax开发精要--概念、案例与框架》<br/><a href="http://www.china-pub.com/computers/common/info.asp?id=30006" target="_blank" rel="external">http://www.china-pub.com/computers/common/info.asp?id=30006</a><br/>[Page] <br/><br/><br/>--------------------------------------------------------------------------------<br/><br/>五.部分技术文章<br/><a href="http://www.dragonson.com/doc/ajax.html" target="_blank" rel="external">http://www.dragonson.com/doc/ajax.html</a><br/>Ajax内部交流文档 <br/><a href="http://info96.k12studio.com/~nio/comments.php?id=242_0_1_0_C" target="_blank" rel="external">http://info96.k12studio.com/~nio/comments.php?id=242_0_1_0_C</a><br/>简单地对 Ajax 进行描述介绍 <br/><a href="http://www.adaptivepath.com/publ" target="_blank" rel="external">http://www.adaptivepath.com/publ</a> ... archives/000385.php<br/>Ajax: A New Approach to Web Applications <br/><a href="http://jibbering.com/2002/4/httprequest.html" target="_blank" rel="external">http://jibbering.com/2002/4/httprequest.html</a><br/>Using the XML HTTP Request object <br/><a href="http://developer.apple.com/internet/webcontent/xmlhttpreq.html" target="_blank" rel="external">http://developer.apple.com/internet/webcontent/xmlhttpreq.html</a><br/>Dynamic HTML and XML: The XMLHttpRequest Object <br/><a href="http://del.icio.us/popular/ajax" target="_blank" rel="external">http://del.icio.us/popular/ajax</a><br/>del.icio.us / popular / ajax <br/><a href="http://www.fiftyfoureleven.com/r" target="_blank" rel="external">http://www.fiftyfoureleven.com/r</a> ... ttprequest/examples<br/>XMLHttpRequest &amp; Ajax Working Examples <br/><a href="http://www.xml.com/lpt/a/2005/02/09/xml-http-request.html" target="_blank" rel="external">http://www.xml.com/lpt/a/2005/02/09/xml-http-request.html</a><br/>Very Dynamic Web Interfaces <br/><a href="http://www.standards-schmandards.com/index.php?2005/03/01/16-ajax-and-accessibility" target="_blank" rel="external">http://www.standards-schmandards.com/index.php?2005/03/01/16-ajax-and-accessibility</a><br/>AJAX and Accessibility <br/><a href="http://www.xml.com/lpt/a/2005/05/11/ajax-error.html" target="_blank" rel="external">http://www.xml.com/lpt/a/2005/05/11/ajax-error.html</a><br/>Errors and AJAX <br/><a href="http://www.softwareas.com/ajax-patterns" target="_blank" rel="external"><a href="http://www.softwareas.com/ajax-patterns" target="_blank" rel="external">http://www.softwareas.com/ajax-patterns</a></a><br/>AJAX Patterns: Design Patterns for AJAX Usability <br/><a href="http://www.backbase.com/download/Whitepaper%20Backbase%20AJAX%20and%20Beyond.pdf" target="_blank" rel="external">http://www.backbase.com/download/Whitepaper%20Backbase%20AJAX%20and%20Beyond.pdf</a><br/>Whitepaper Backbase AJAX and Beyond <br/><a href="http://www.ajaxpatterns.org" target="_blank" rel="external">http://www.ajaxpatterns.org</a>/index.php?title=Main_Page<br/>AJAX patterns <br/><a href="http://www.onlamp.com/pub/a/onlamp/2005/05/19/xmlhttprequest.html" target="_blank" rel="external">http://www.onlamp.com/pub/a/onlamp/2005/05/19/xmlhttprequest.html</a><br/>A Simpler Ajax Path <br/>]]></description>
		</item>
		
			<item>
			<link>http://bokee.shinylife.net/blog/article.asp?id=577</link>
			<title><![CDATA[jquery中英文对照手册(chm)]]></title>
			<author>paulleder@msn.com(PaulLeder)</author>
			<category><![CDATA[Ajax]]></category>
			<pubDate>Tue,17 Jul 2007 21:13:54 +0800</pubDate>
			<guid>http://bokee.shinylife.net/blog/default.asp?id=577</guid>
		<description><![CDATA[直接点击下载<a href="http://www.kuomart.com/blog/my_result/jquery_api.chm" target="_blank" rel="external">http://www.kuomart.com/blog/my_result/jquery_api.chm</a><br/><br/><img src="http://bokee.shinylife.net/blog/images/download.gif" alt="下载文件" style="margin:0px 2px -4px 0px"/> <a href="http://bokee.shinylife.net/blog/attachments/month_0707/72007717211345.chm" target="_blank">点击下载此文件</a><br/>]]></description>
		</item>
		
			<item>
			<link>http://bokee.shinylife.net/blog/article.asp?id=563</link>
			<title><![CDATA[ASP解决AJAX带来的码问题]]></title>
			<author>paulleder@msn.com(PaulLeder)</author>
			<category><![CDATA[Ajax]]></category>
			<pubDate>Fri,06 Jul 2007 14:51:14 +0800</pubDate>
			<guid>http://bokee.shinylife.net/blog/default.asp?id=563</guid>
		<description><![CDATA[只用在后台处理页面加上<br/>Response.ContentType = &#34;text/html&#34; <br/>Response.Charset = &#34;GB2312&#34;<br/>即可．<br/>需要放在顶部．]]></description>
		</item>
		
			<item>
			<link>http://bokee.shinylife.net/blog/article.asp?id=437</link>
			<title><![CDATA[XMLHTTP对象及其方法]]></title>
			<author>paulleder@msn.com(PaulLeder)</author>
			<category><![CDATA[Ajax]]></category>
			<pubDate>Mon,06 Nov 2006 10:18:56 +0800</pubDate>
			<guid>http://bokee.shinylife.net/blog/default.asp?id=437</guid>
		<description><![CDATA[MSXML中提供了Microsoft.XMLHTTP对象，能够完成从数据包到Request对象的转换以及发送任务。 <br/>创建XMLHTTP对象的语句如下： <br/>Set objXML = Cr&#101;ateObject(&#34;Msxml2.XMLHTTP&#34;) 或<br/>Set objXML = Cr&#101;ateObject(“Microsoft.XMLHTTP”)<br/>&#39; o&#114;, for version 3.0 of XMLHTTP, use:<br/>&#39; Set xml = Server.Cr&#101;ateObject(&#34;MSXML2.ServerXMLHTTP&#34;)<br/>对象创建后调用Open方法对Request对象进行初始化，语法格式为： <br/>poster.open http-method, url, async, userID, password <br/>Open方法中包含了5个参数，前三个是必要的，后两个是可选的(在服务器需要进行身份验证时提供)。参数的含义如下所示：&nbsp;&nbsp;<br/>http-method： HTTP的通信方式，比如GET或是 POST <br/>url： 接收XML数据的服务器的URL地址。通常在URL中要指明 ASP或CGI程序 <br/>async： 一个布尔标识，说明请求是否为异步的。如果是异步通信方式(true)，客户机就不等待服务器的响应；如果是同步方式(false)，客户机就要等到服务器返回消息后才去执行其他操作 <br/>userID 用户ID，用于服务器身份验证 <br/>password 用户密码，用于服务器身份验证 <br/>XMLHTTP对象的Send方法 <br/>用Open方法对Request对象进行初始化后，调用Send方法发送XML数据： <br/>poster.send XML-data <br/>Send方法的参数类型是Variant，可以是字符串、DOM树或任意数据流。发送数据的方式分为同步和异步两种。在异步方式下，数据包一旦发送完毕，就结束Send进程，客户机执行其他的操作；而在同步方式下，客户机要等到服务器返回确认消息后才结束Send进程。 <br/>XMLHTTP对象中的readyState属性能够反映出服务器在处理请求时的进展状况。客户机的程序可以根据这个状态信息设置相应的事件处理方法。属性值及其含义如下表所示： <br/>值 说明 <br/>0 Response对象已经创建，但XML文档上载过程尚未结束 <br/>1 XML文档已经装载完毕 <br/>2 XML文档已经装载完毕，正在处理中 <br/>3 部分XML文档已经解析 <br/>4 文档已经解析完毕，客户端可以接受返回消息<br/>客户机处理响应信息 <br/>客户机接收到返回消息后，进行简单的处理，基本上就完成了C/S之间的一个交互周期。客户机接收响应是通过XMLHTTP对象的属性实现的： <br/>● responseTxt：将返回消息作为文本字符串； <br/>● responseXML：将返回消息视为XML文档，在服务器响应消息中含有XML数据时使用； <br/>● responseStream：将返回消息视为Stream对象。 <br/><br/>下面的xml文件是动态生成的最后用xmlHTTP传送出去，这是一个在客户端JavaScript脚本里的内容，当然你也可以写在服务器，但是要相应的改一些东西：（仅供大家参考，了解它的用法）<br/>var xmlDoc=new ActiveXObject(&#34;MSXML2.DOMDocument&#34;);<br/>flag=xmlDoc.loadXML(&#34;&#34;);<br/><br/>&nbsp;&nbsp;newNode =xmlDoc.cr&#101;ateElement(&#34;编码&#34;)<br/>&nbsp;&nbsp;MarkNode=xmlDoc.documentElement.appendChild(newNode);<br/>&nbsp;&nbsp;newNode =xmlDoc.cr&#101;ateElement(&#34;StartMark&#34;)<br/>&nbsp;&nbsp;newNode.text=StartMark;<br/>&nbsp;&nbsp;MarkNode.appendChild(newNode)<br/>&nbsp;&nbsp;newNode =xmlDoc.cr&#101;ateElement(&#34;EndMark&#34;)<br/>&nbsp;&nbsp;newNode.text=EndMark;<br/>&nbsp;&nbsp;MarkNode.appendChild(newNode)<br/>&nbsp;&nbsp;<br/>&nbsp;&nbsp;newNode =xmlDoc.cr&#101;ateElement(&#34;日期&#34;)<br/>&nbsp;&nbsp;DateNode=xmlDoc.documentElement.appendChild(newNode);<br/>&nbsp;&nbsp;newNode =xmlDoc.cr&#101;ateElement(&#34;StartDate&#34;);<br/>&nbsp;&nbsp;newNode.text=StartDate;<br/>&nbsp;&nbsp;DateNode.appendChild(newNode)<br/>&nbsp;&nbsp;newNode =xmlDoc.cr&#101;ateElement(&#34;EndDate&#34;)<br/>&nbsp;&nbsp;newNode.text=EndDate;<br/>&nbsp;&nbsp;DateNode.appendChild(newNode);<br/>&nbsp;&nbsp;<br/>&nbsp;&nbsp;newNode =xmlDoc.cr&#101;ateElement(&#34;数量&#34;)<br/>&nbsp;&nbsp;SLNode =xmlDoc.documentElement.appendChild(newNode);<br/>&nbsp;&nbsp;newNode =xmlDoc.cr&#101;ateElement(&#34;StartSL&#34;)<br/>&nbsp;&nbsp;newNode.text=StartShuL <br/>&nbsp;&nbsp;SLNode.appendChild(newNode)<br/>&nbsp;&nbsp;newNode =xmlDoc.cr&#101;ateElement(&#34;EndSL&#34;);<br/>&nbsp;&nbsp;newNode.text=EndShuL<br/>&nbsp;&nbsp;SLNode.appendChild(newNode);<br/>&nbsp;&nbsp;<br/>&nbsp;&nbsp;newNode =xmlDoc.cr&#101;ateElement(&#34;单价&#34;)<br/>&nbsp;&nbsp;DJNode =xmlDoc.documentElement.appendChild(newNode)<br/>&nbsp;&nbsp;newNode =xmlDoc.cr&#101;ateElement(&#34;StartDJ&#34;)<br/>&nbsp;&nbsp;newNode.text=StartDanJ;<br/>&nbsp;&nbsp;DJNode.appendChild(newNode);<br/>&nbsp;&nbsp;newNode =xmlDoc.cr&#101;ateElement(&#34;EndDJ&#34;)<br/>&nbsp;&nbsp;newNode.text=EndDanJ;<br/>&nbsp;&nbsp;DJNode.appendChild(newNode);<br/>&nbsp;&nbsp;<br/>&nbsp;&nbsp;newNode =xmlDoc.cr&#101;ateElement(&#34;金额&#34;)<br/>&nbsp;&nbsp;JENode =xmlDoc.documentElement.appendChild(newNode)<br/>&nbsp;&nbsp;newNode =xmlDoc.cr&#101;ateElement(&#34;StartJE&#34;)<br/>&nbsp;&nbsp;newNode.text=StartJinE<br/>&nbsp;&nbsp;JENode.appendChild(newNode)<br/>&nbsp;&nbsp;newNode =xmlDoc.cr&#101;ateElement(&#34;EndJE&#34;)<br/>&nbsp;&nbsp;newNode.text=EndJinE<br/>&nbsp;&nbsp;JENode.appendChild(newNode)<br/>&nbsp;&nbsp;<br/>&nbsp;&nbsp;newNode =xmlDoc.cr&#101;ateElement(&#34;仓库代码&#34;)<br/>&nbsp;&nbsp;newNode.text=CK;<br/>&nbsp;&nbsp;xmlDoc.documentElement.appendChild(newNode)<br/>&nbsp;&nbsp;<br/>&nbsp;&nbsp;newNode =xmlDoc.cr&#101;ateElement(&#34;票号&#34;)<br/>&nbsp;&nbsp;newNode.text=RKPH;<br/>&nbsp;&nbsp;xmlDoc.documentElement.appendChild(newNode)<br/>&nbsp;&nbsp;<br/>&nbsp;&nbsp;newNode =xmlDoc.cr&#101;ateElement(&#34;单位代码&#34;)<br/>&nbsp;&nbsp;newNode.text=CorpName;<br/>&nbsp;&nbsp;xmlDoc.documentElement.appendChild(newNode)<br/>&nbsp;&nbsp;<br/>&nbsp;&nbsp;newNode =xmlDoc.cr&#101;ateElement(&#34;BiaoShi&#34;)<br/>&nbsp;&nbsp;newNode.text=Biaoshi<br/>&nbsp;&nbsp;xmlDoc.documentElement.appendChild(newNode)<br/>&nbsp;&nbsp;<br/>&nbsp;&nbsp;newNode =xmlDoc.cr&#101;ateElement(&#34;FindCate&#34;)<br/>&nbsp;&nbsp;newNode.text=FindCate<br/>&nbsp;&nbsp;xmlDoc.documentElement.appendChild(newNode)<br/>&nbsp;&nbsp;<br/>&nbsp;&nbsp;var xh =new ActiveXObject(&#34;MSXML2.XMLHTTP&#34;)<br/>&nbsp;&nbsp;xh.open(&#34;POST&#34;,&#34;Find.asp&#34;,false)<br/>&nbsp;&nbsp;xh.setRequestHeader(&#34;Content-Type&#34;,&#34;text/xml&#34;)<br/>&nbsp;&nbsp;xh.setRequestHeader(&#34;Content-Type&#34;,&#34;gb2312&#34;)<br/>&nbsp;&nbsp;xh.send(xmlDoc);<br/>我的每一个newNode的text值是一个变量，也就是我客户端form 中input的值,<br/>]]></description>
		</item>
		
			<item>
			<link>http://bokee.shinylife.net/blog/article.asp?id=431</link>
			<title><![CDATA[XMLHTTP得到源码]]></title>
			<author>paulleder@msn.com(PaulLeder)</author>
			<category><![CDATA[Ajax]]></category>
			<pubDate>Mon,06 Nov 2006 10:04:02 +0800</pubDate>
			<guid>http://bokee.shinylife.net/blog/default.asp?id=431</guid>
		<description><![CDATA[&lt;%<br/>&#39;作者:小男<br/>&#39;<a href="http://www.sman.cn/" target="_blank" rel="external">http://www.sman.cn/</a><br/><br/>Response.Write GetTheHTMLCode(&#34;<a href="http://www.baidu.com" target="_blank" rel="external">http://www.baidu.com</a>&#34;) <br/>&#39;用XMLHTTP得到源码<br/>Function GetTheHTMLCode(Url) <br/>&nbsp;&nbsp;&nbsp;&nbsp;Dim Http<br/>&nbsp;&nbsp;&nbsp;&nbsp;Set Http=server.cr&#101;ateobject(&#34;MSXML2.XMLHTTP&#34;)<br/>&nbsp;&nbsp;&nbsp;&nbsp;Http.open &#34;GET&#34;,Url ,false<br/>&nbsp;&nbsp;&nbsp;&nbsp;Http.send()<br/>&nbsp;&nbsp;&nbsp;&nbsp;If Http.readystate&lt;&gt;4 then <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Exit Function<br/>&nbsp;&nbsp;&nbsp;&nbsp;End if<br/>&nbsp;&nbsp;&nbsp;&nbsp;GetTheHTMLCode = BytesToBSTR(Http.responseBody,&#34;GB2312&#34;)<br/>&nbsp;&nbsp;&nbsp;&nbsp;Set Http=nothing<br/>End Function<br/>&#39;中文乱码处理<br/>Function BytesToBstr(body,Cset) <br/>&nbsp;&nbsp;&nbsp;&nbsp;dim objstream<br/>&nbsp;&nbsp;&nbsp;&nbsp;set objstream = Server.Cr&#101;ateObject(&#34;adodb.stream&#34;)<br/>&nbsp;&nbsp;&nbsp;&nbsp;objstream.Type = 1<br/>&nbsp;&nbsp;&nbsp;&nbsp;objstream.Mode =3<br/>&nbsp;&nbsp;&nbsp;&nbsp;objstream.Open<br/>&nbsp;&nbsp;&nbsp;&nbsp;objstream.Write body<br/>&nbsp;&nbsp;&nbsp;&nbsp;objstream.Position = 0<br/>&nbsp;&nbsp;&nbsp;&nbsp;objstream.Type = 2<br/>&nbsp;&nbsp;&nbsp;&nbsp;objstream.Charset = Cset<br/>&nbsp;&nbsp;&nbsp;&nbsp;BytesToBstr = objstream.ReadText <br/>&nbsp;&nbsp;&nbsp;&nbsp;objstream.Close<br/>&nbsp;&nbsp;&nbsp;&nbsp;set objstream = nothing<br/>End Function<br/>%&gt;]]></description>
		</item>
		
			<item>
			<link>http://bokee.shinylife.net/blog/article.asp?id=400</link>
			<title><![CDATA[创建XMLHTTP和XMLDOM]]></title>
			<author>paulleder@msn.com(PaulLeder)</author>
			<category><![CDATA[Ajax]]></category>
			<pubDate>Fri,06 Oct 2006 10:38:14 +0800</pubDate>
			<guid>http://bokee.shinylife.net/blog/default.asp?id=400</guid>
		<description><![CDATA[//Cr&#101;ate XMLDOM Object<br/>function cr&#101;ateXMLDOM(){<br/>&#160;&#160;&#160;&#160;var arrXmldom=[&#34;Microsoft.XMLDOM&#34;,&#34;Msxml2.DOMDocument&#34;,&#34;Msxml2.DOMDocument.3.0&#34;,&#34;Msxml2.DOMDocument.4.0&#34;,&#34;Msxml2.DOMDocument.5.0&#34;];<br/>&#160;&#160;&#160;&#160;for(var i=0;i&lt;arrXmldom.length;i++){<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;try{<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;var xmlDomValue=new ActiveXObject(arrXmldom[i]);<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;return xmlDomValue;<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;}catch(e){<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;//忽略错误，继续下次执行<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;}<br/>&#160;&#160;&#160;&#160;}<br/>&#160;&#160;&#160;&#160;return null;<br/>}<br/><br/>//Cr&#101;ate XMLHTTP Object<br/>function cr&#101;ateXMLHTTP(){<br/>&#160;&#160;&#160;&#160;var arrXmlhttp=[&#34;Microsoft.XMLHTTP&#34;,&#34;Msxml2.XMLHTTP&#34;,&#34;MSXML2.ServerXMLHTTP&#34;];<br/>&#160;&#160;&#160;&#160;for(var i=0;i&lt;arrXmlhttp.length;i++){<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;try{<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;var xmlHttpValue=new ActiveXObject(arrXmlhttp[i]);<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;return xmlHttpValue;<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;}catch(e){<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;//忽略错误，继续下次执行<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;}<br/>&#160;&#160;&#160;&#160;}<br/>&#160;&#160;&#160;&#160;return null;<br/>}]]></description>
		</item>
		
</channel>
</rss>
