Seamlessly working with the Server

不換頁技術

Why No Refresh

Web 2.0 的一個主要概念,就是將瀏覽器視為一個應用程式(也就是 Web Application),讓 User 感覺不到網頁究竟跟一般的視窗應用程式有什麼差異。要達到這樣的目標,就需要用到大量的 DHTML 技巧,如拖曳、動畫效果等,以及本次要介紹的不換頁技術。

傳統的網頁中,不管做任何事,都必須重新整理網頁一次,譬如新增一筆資料、換頁、查詢、修改(範例網頁:http://disty.aaeon.com.tw/eFunnel/。這樣的做法會有以下的缺點:

以視窗應用程式的觀點來看,做任何事都必須重新整理勢必是一件很不合理的事吧。所以當整個潮流都移向「網路應用程式」的當下,不重新整理的技術,變得越來越重要,也是一個不可不會的基本功夫。今天要介紹的主要有下列幾種:


Window Pop Up:利用跳出視窗更新網頁

在跳出視窗尚不會被攔截的時代,常有許多網站會利用這樣的方式來做不換頁的更新。而現在主流的瀏覽器 IE 、Firefox 預設已經會攔截跳出視窗,用這種方式來更新已經少之又少了。

window.open()

我們可以利用跳出的視窗去取得伺服器端的資料,再把取得的資料寫回原本的視窗。這是一種蠻直覺的做法,剛剛提到「封鎖快顯視窗」的緣故,若這個跳出視窗的動作不是由使用者所驅動,那麼十之八九會被擋掉,功能就會因此而失效了。

輸入帳號取得使用者的 Email (ASP Code) | 自動取得伺服器上的時間(被視窗封鎖的失敗範例)

window.showModalDialog()

由於視窗內建的 window.alert(), window.prompt(), winfow.confirm() 外觀都是一成不變的,基於這個問題,微軟就發展出了 window.showModalDialog。showModalDialog 的中文名稱就是「對話視窗」,跟 alert(), prompt(), confirm(), 一樣,使用者必須關閉此視窗、或按下某個 button 才可以繼續下一步,也可以稱為「同步化作業」(必須等待處理完畢、不能在等待的時間作其他事情)。這是一個蠻好使用的方式,但很可惜的是 FireFox 完全不支援、而且在 IE 如果不是使用者所驅動、也一樣會有封鎖視窗的問題在。

什麼是 showModalDialog | 查詢使用者的 Email (ASP Code)

Frame:利用框架更新網頁

這也是一種傳統的做法,但是到目前都還是歷久不衰。

Frameset

我們可以用 Frame Set 的方式將網頁一切為二,一個 Viewable Frame 是使用者所檢視的網頁、一個是看不到(寬度設為 0)的 Hidden Frame。假設網友在其所檢視的網頁按下了一個連結,這個連結的目標(target)其實是指向到 Hidden Frame 的,在 Hidden Frame 讀取此網頁完畢之後,就可以把資料輸出到 Viewable Frame 中的一個 div 供使用者觀看。


<!-- 設第二個 Frame 顯示高度為零 -->
<frameset cols="100%,*">
    <frame src="view.html" name="view"></frame>
    <frame src="hidden.html" name="hidden"></frame>
</frameset>
教學:載入文件到目前的網頁中 | 完成

其實可以把這種隱藏的 Frame 想成是一種 Buffer 的觀念,等 Buffer 區讀完之後才會放到正式頁面上

優點:這種方法在比較舊的瀏覽器如 Netscape 4 也可以使用、資料傳輸量不限

缺點:無法做搜尋引擎最佳化(SEO)、無法存取跨網域的資料

註:會有上一頁的歷史紀錄,但無法歸納為優點或缺點,端看開發人員的使用角度。像 AJAX 無法有上一頁下一頁的歷史紀錄,對很多以 Usability 為考量的網站就是一種致命傷。

IFrame

跟 Frameset 的原理相同,只是我們不需要再包裝一層,比較容易實做。可以放在現有網頁的任何地方,或者是動態產生再加以利用。

<html>
<head>
<title>Example</title>
<style>

iframe {display:none;}

</style>
</head>
<body>
<h1>Title</h1>
<p>Content</p>

<div id="view">Show Area</div>

<iframe src="about:blank" name="buffer"></iframe>

</body>
</html>
Tab Framework

優缺點與 Frame 一樣,但 SEO 較好。由於 Iframe 是比 Frame 新一些的技術,所以剛剛提到的 NN4 就沒辦法使用 iframe 來做了


Cookies

這種技術是利用 Cookies 不管在 Client 端或 Server 端都可以被存取的特性,我們可以在在頁面上想辦法製造一些與 Server 端的微量變動,讓 Server 接到改變後的 Client 端的請求。那麼,我們該怎麼製造出不整頁重新整理的微量變動呢?有下列兩種方法:

Image Replacement


<!-- 欲送出的變數值 -->
請輸入使用者帳號:<input id="txt" type="text" value="JosephJ"/>

<!-- 回傳的訊息會顯示在此 -->
<p id="msg">在您輸入的過程就會幫您檢查此帳號是否存在唷...</p>

<!-- 被用來發出 Request 的圖片 -->
<img id="img" alt="hidden image"/>

圖片<img/>本身就具有可以利用 js 做動態更替載入的特性。在這邊我們不是要顯示圖片,而是利用這一個特性將我們帶有參數的網址送出、將 src 設為此帶有參數的網址,那麼自然就會對 Server 做出 GET 的 HTTP Request(想當然爾,圖片就是破圖)。

至於資料的傳回,我們就不再利用圖片了!而是在負責的 Server 端網頁(如 PHP 或 ASP),將所需的資料寫入至 Cookie 中。

最後一步,我們再利用 Javascript 來取得這更新的 Cookies 顯示在網頁上。如此一來,整個網頁不需要重新整理就可以抓到資料了!

範例:增測使用者帳號是否存在 ( Server 端程式碼 ) | 範例改進:每打一個字就做一次增測

圖片替換的優點:不影響 SEO。

圖片替換的缺點:Cookies 不能用的時候就失效了、只能傳送少量的資訊(Cookies 最多只有 4KB 的容量)、無法存取遠端資訊、若未來對 img 做出安全性限制(僅可使用圖片格式),屆時就無法利用此方法取得資訊。

204 Piggyback

其實這是使用 HTTP 的狀態 (如 5XX 是伺服器錯誤)。利用這種技巧,連一個假的圖片都省掉了,除了 Js 的處理外,你可以用一般的方式連結、或送出表單到某一特定的網頁(Server-side Language)。這個特定的網頁有一個很重要的設定:就是必須將網頁的 Header 設為 HTTP/1.1 204 No Content(可參考:Status Code Definitions

PHP 的設定法:

<?php header('HTTP/1.1 204 No Content'); ?>
ASP 的設定法:

<% Response.Status = "204 No Content" %>

204 No Content 代表了網頁收到了 Request,但是不做任何的回應。所以當這樣設定了之後,瀏覽器的確會有送出的動作,但是你可以發現所在的網頁將是會靜止不動的。這樣一來,我們「製造 Request 但不重新整理網頁」的目標就達成了。這個目標的網頁,如上面的圖片替代方法,一樣會把所需的回應寫到 Cookies 中。開發者再一次,又可以在 Client 端利用 Js 取得由 Server 端所變動的 Cookies

範例:以使用者帳號取得其資訊 | Server 端程式碼 | Amazon 的評比 | K+ 會用到的 Module

優點:不影響 SEO、製作方法與開法一般網頁相似、比圖片置換的方法更為直覺、讓不更新網頁的上傳得以達成(另開新視窗也可達成)。

缺點:同 Image Replacement。


External Javascript

簡單來說,這個技巧就是利用網頁允許使用外部 Javascript 的特性。而,外部 Javascript 的 src 也跟圖片一般,可以動態改變,所以一樣可以達到不 Refresh 整個網頁就發出 HTTP Request 的目標。Even Better,在上述的方法中,沒有一個是可以跨網域的!但是引用外部 Javascript 有不限於本地端的特性(我們時常會連結到其他人 Server 上的 js),所以這個方法是可以對非本地端的網頁發出 HTTP Request 的。我們可以把 Js 當作是一個資料來源。

<html>
<head>
<title>Example</title>
<script src="http://www.benesse.com.tw/tool/city.asp?city=台北市"></script>
<script>
... 在這裡處理上面那隻 script src 的參數值 ...
... 例如將台北市改為台中市 ...
</script>
</head>
<body>
... 網頁內容 ...
</body>
</html>

如同原始碼,我寫了一個以縣市取得相關鄉鎮市區的 External Javascript(按此觀看),你可以從原始檔中發現我們的 js 其實是連到 http://www.benesse.com.tw/tool/address.asp 這個 ASP 網頁,為什麼是 ASP 網頁呢?就是因為希望 js 的內容可以因應帶入的參數有所不同、傳回的東西也就會不相同。您可以將此網頁的原始碼複製貼上到任何地方,你會發現、在有網際網路的情況下、都是可以正常使用的!

範例二:delicious 也有提供這樣的 Feed, 我做了一些改進,你可以自選使用者及觀看筆數(按此觀看)。其實只要格式是 JSON 就可以拿來當 External Javascript

範例三:其實在 Yahoo!Kimo 也有用到 External Javascript 的技術喔,就是 Overture 的 Linkspot 廣告,是為了要能夠放在別的網站,如 MSN、蘋果日報、東森新聞報等網站,在別人的網站只要放一段我們的原始碼,就可以用我們的服務、達到「隨插即用」的效果(按此觀看

範例四:最近剛好有機會要做 Overture 的 eCM 廣告,把上面的 Linkspot 給淘汰掉 :D (按此觀看)、(我自己做好玩的測試樣式的版本

優點:可存取跨網欲的資料

缺點:使用他人 Js 有安全性疑慮(按此觀看)、必須仰賴別人的伺服器作業、未來安全性升高有可能禁止遠端的 Js 存取。


XMLHttp

看了以上的各種技術,除了 Remote Scripting 外,其他的技巧似乎都像是一種「Hack」(非正規的做法),有可能未來某一天都被瀏覽器所禁止掉。不過這樣的瓶頸,隨著 XMLHttp 的誕生有了更好的解決之道。

XMLHttp 首先由 Microsoft 實作,是一種可以單純由 Javascript 對後端發出 Http Request、並且接著取得回傳結果的技術。藉由這種方式,開發者就不需要再藉著隱藏的 Frame 、Image、Cookies 或開新視窗來傳遞資料了、讓技術回歸正當的做法。附帶一提的是,這是個老掉牙的技術,直到最近才因為行銷人員將之重新包裝成「AJAX」才大紅特紅。

IE 7 以前, XMLHttp 都還是用 ActiveX 來做


var oRequest = new ActiveXObject("Microsoft.XMLHTTP");

但是在 FireFox 就直接有 window.XMLHttpRequest 這個物件了~


var oRequest = new XMLHttpRequest();

基本的呼叫函式可以這樣寫:


//全域物件
var http_request = false;
function makeRequest(url) {
    if (window.XMLHttpRequest) { // Mozilla [11], Safari,...
        http_request = new XMLHttpRequest();
    }
    else if (window.ActiveXObject) { // IE
        http_request = new ActiveXObject("Microsoft.XMLHTTP");
    }
    // 指定後續處理的函式 (Callback Function)
    http_request.onreadystatechange = alertContents;
    http_request.open('GET', url, true);
    http_request.send(null);
}

alertContent 函式

function alertContents() {
    if (http_request.readyState == 4) {
        if (http_request.status == 200) {
            alert(http_request.responseText);
        }
        else {
            alert('There was a problem with the request.');
        }
    }
}

使用上面兩個函式就可以輕鬆地使用 XMLHttp 來取得資料,以下的範例是我的兩個作品:

討論區,利用 AJAX 達成不換頁、讀取內容 | AJAX DataGrid (創意來源)

Problem - Cross Domain

XMLHttp 雖然好用,但是有一個缺憾,跟 Frame 或 WindowsPopup 的技術一樣、它不能取得自身網域外的資料。這點我們必須要配合後端的技術來解決。可以參考 Yahoo! Developer 的這篇文章:HOWTO: Use a Web Proxy for Cross-Domain XMLHttpRequest Calls

藉由這個 proxy.php,我們就可以存取遠端的資料,這樣一來,我們就可以利用 Flickr, Upcoming, Delicious 等服務來架設我們的個人網站,而不用自己建個資料庫,是不是令人很興奮呢?

利用 Yahoo 的 API 來做自己網頁的搜尋引擎 |

練習區

以下的區塊是給您練習用的

 
Joseph Jiang
webmaster@swingingbird.com