最近更新: 2007-02-20

網路服務與純 JavaScript 應用之 JSON 資料包裹解決方案

Tags: ajax json web2.0

在 Web 2.0 的浪潮下,有愈來愈多的網路服務推出,如網路相簿、網路書籤、網路書櫃等等。大多數網路服務都有提供 Blog 使用的小工具 (或稱 Badge) ,從軟體設計的觀點來看,這些小工具才是我們在談的「網路服務」、「服務元件 (service compoent)」。

我最近在玩網路書籤提供的這些服務元件,就我觀察這些服務元件主要分兩種形式:一、以一段固定的 JavaScript 程式碼輸出網頁內容;二、僅提供 XML/JSON 資料,讓使用者自己處理程式邏輯。這兩種形式各有限制。第一種包辦了資料和程式邏輯,使用者只需/只能用 CSS 調整外觀;而且因為包含了 JavaScript 的程式邏輯,所以不同服務者提供的服務元件放在同一個頁面時可能會相衝,有我無他、或者大家一起掛。第二種則受限於 XMLHttpRequest 的安全性限制,基本上不能做成純 JavaScript 的應用。

我想了想,其實有一種介於這兩種型式的服務提供方案。我把這個方案提供給 Hemidemi 的管理者參考了,見 Hemidemi 建議區 。我在這裡也敘述一下方案內容吧。

我想到的解決方案介於上述提到的兩種形式之間,它是一段 JavaScript 程式碼,但它所提供的程式碼只是 JSON 資料的包裹。

Hemidemi 目前提供的服務元件為例。 Hemidemi 提供了一項查詢指定網址有幾人收錄到書籤中的服務項目,為提供 RSS (XML) 文件的服務形式。先將網址以 MD5 雜湊法得出一字串,以該字串為 ID 組成查詢服務的 REST URL ,如http://www.hemidemi.com/rss/bookmark/[md5(document.URL)]/users.xml 。但這有兩個應用上的問題:

  1. ID 要用 MD5 函數計算。
  2. 只提供的 XML 文件格式。

ID 要用 MD5 函數計算

乍看之下似乎不是什麼大問題,但是 JavaScript 目前並未內建 MD5 函數,所以我們不能簡單地建立純 JavaScript 的應用。雖然在 JavaScript MD5 網頁中提供了一個採 BSD 軟體授權發佈的 JavaScript 的 MD5 實作函數可用,但對建立純 JavaScript 應用而言已經是一道關卡了。為了一個 MD5 函數,使用者通常得在 server 上實作應用工具,但不是每個使用者都會擁有 server 空間或虛擬主機,因此又形成了一道關卡。雖然有些使用者在自己的主機上實作並以自己的資源提供這類服務,但畢竟不是長遠之計。

只提供的 XML 文件格式

若欲用於純 JavaScript 應用之上,便只能透過 XMLHttpRequest 取回 XML 資料。但這又受限於 XMLHttpRequest 不能跨網域的安全性限制,所以又是一個難題。

JSON 資料包裹的解決方案

我想到的解決方案如前所述,是把 JSON 資料用一段 JavaScript 程式碼包裹起來的方案。同樣以 Hemidemi 的書籤收藏使用者查詢服務為例說明實踐細節。

首先,Hemidemi 需要允許使用者用 JavaScript 內建的 encodeURIComponent() 計算網址得出 ID 。事實上, URL 本身就是一個 unique key ,而 encodeURIComponent() 計算出的字串只是比較長而已,不似 MD5 函數固定是 32 個字元長度。這不妨礙我們以之為 ID 組成查詢服務用的 REST URL。

查詢服務則要回傳一段 JavaScript 程式碼,更精確的說,是一段包著 JSON 資料的 JavaScript 外層 (即 JSON資料包裹)。範例如下列:

/***
Start of response code (JSON data with JavaScript shell)
***/
if (!this.Hemidemi) { /*If there is no object Hemidemi, new one.*/
    this.Hemidemi = {};
}

/* Open object Hemidemi and add new property 'users'
users 的內容跟 RSS 回傳的資料一樣,但格式是 JSON 。*/
this.Hemidemi.users =
{
    'title' : '書籤標題',
    'link' : 'http://example.com/',
    'description' : '書籤說明、引述...',
    'ttl' : 40,
    'lastBuildDate' : '',
    'items' : [
        {
            'title': '標題xx',
            'author': '收藏者1',
            'description': '描述',
            'pubDate': '',
            'guid': '',
            'link': '',
            'image': {
                'url': '',
                'title': '',
                'width': 60,
                'height': 60
            }
        },
        {
            'title': '標題yy',
            'author': '收藏者2',
            'description': '描述',
            'pubDate': '',
            'guid': '',
            'link': '',
            'image': {
                'url': '',
                'title': '',
                'width': 60,
                'height': 60
            }
        }
    ]

}
;
/***
End of response code
***/

第11到48行的內容,純粹是一個 JSON 資料。這表示實踐此方案,首先應先實作提供 JSON 資料文件的服務元件。接著再以此為基礎實作一個將 JSON 資料包著 JavaScript 程式碼的回應內容就可以完成 JSON 資料包裹形式的服務元件。

使用者的使用過程大致上只要在頁面中加上如下列的程式碼即可:

function queryHemidemiUsersHandler() {
    window.alert('' + Hemidemi.users.items.length + ' 人收藏此文章。');
}

function queryHemidemiUsers() {
    var restId = encodeURIComponent(document.URL);
    var restUrl = 'http://www.hemidemi.com/bookmark/' + restId + '/users.js';
    var restJs = document.createElement('script');
    restJs.type = 'text/javascript';
    restJs.src = restUrl;
    document.getElementsByTagName('head')[0].appendChild(restJs);

    var intervalQueryHemidemiUsers = setInterval(
        function() {
            if (Hemidemi.users) {
                clearInterval(intervalQueryHemidemiUsers );
                queryHemidemiUsersHandler();
            }
        },
        100
    );
}

if (window.attachEvent) window.attachEvent('onload', queryHemidemiUsers);
else window.addEventListener('load', queryHemidemiUsers, false);

關於動態載入外部 JavaScript 程式碼的細節請參考《Load and Execute JavaScript on Demand, by createElement》。 JSON 資料包裹形式的服務元件只完成資料的載入動作,不多做其他程式邏輯,所以可以確保不同服務元件的相容性,並保有讓使用者以 JavaScript 自行設計網頁應用的彈性。

相關文章
樂多舊網址: http://blog.roodo.com/rocksaying/archives/2749975.html

樂多舊回應
未留名 (#comment-4017713)
Thu, 22 Feb 2007 03:48:10 +0800
好像還有一種格式是gdate的,不過程是我也不是很熟,在孤勾看過.
未留名 (#comment-4023779)
Fri, 23 Feb 2007 09:32:14 +0800
Google 的 Using JSON with Google Data APIs

其實我這裡說的概念,就是在 Google 看到的。差別在於 Google 的方式要求使用者指定一個 javascript 的自定函數名稱,它會把 JSON 資料做為引數直接傳給該函數。而我這邊是直接指派變數。繼續閱讀:Google 的方式