没有X的Ajax,没有尖括号的微格式(1)(2)
JSON 的 REST
很多使用 JSON 的例子说明浏览器如何使用 GET 从服务器上接收 JSON 消息。但是 REST 范例有四个动词:GET、POST、PUT 和 DELETE,它们的存在都有一个理由。GET 用于没有副作用(即 GET 应该是等幂的)地检索 Web 资源,POST 用于创建新的资源、PUT 用于更新已有的资源,DELETE 用于删除资源。因为我们要做 REST 城邦的好市民,就建立一个简单的框架使用这四个动词传递 JSON 数据吧。
下面是一个 CGI 程序的 Python 代码,封装了传递 JSON 代码的想象得到的最简单的骨架结构。它使用 Bob Ippolito 的 simplejson库解析 JSON,比直接 eval从 Web 接收的字符串更安全。当然,真正创建一个 REST 接口要比这个复杂得多(为每个资源创建 URI 就很麻烦)。最简单的 REST/JSON 服务器如清单 4所示:
清单 4. REST/JSON 服务器
#!/usr/local/bin/python
'''
Minimal JSON REST server
'''
import os
import cgi
import cgitb
cgitb.enable()
import simplejson
sample_data = {'name': 'King Arthur',
'quest': 'To seek the holy grail',
'airspeed_of_unladen_European_swallow': '24 MPH'}
def post(args):
'''
Used to create a new resource
'''
new_uri = 'http://example.org/' # URI of newly created resource
sample_data['result_uri'] = new_uri
print simplejson.dumps(sample_data)
def put(args):
'''
Used to update an existing resource
'''
sample_data.update(args)
print simplejson.dumps(sample_data)
def get(args):
'''
Used for any side-effect free request
'''
print simplejson.dumps(sample_data)
def delete(args):
'''
Used to remove an existing note
'''
print simplejson.dumps({'content':'None'})
def main():
method = os.environ.get('REQUEST_METHOD', 'GET')
if method == 'GET':
args = None
else:
json_value = cgi.FieldStorage().getfirst('json_value')
args = simplejson.loads(json_value)
if method == 'POST':
method = args['method'] # fix for browsers that don't
# send PUT or DELETE properly
# Start an HTTP response
print "Content-type: text/plain"
print ""
# Python dispatch idiom using a dictionary vs. case-statement
dict(POST=post,
PUT=put,
GET=get,
HEAD=get,
DELETE=delete)[method](args)
if __name__ == '__main__':
main() |
清单 4能够处理服务器端 REST 和 JSON 的基本操作。在客户端,Dethe 编写了少量 JavaScript 代码可以嵌入到网页中。该例还使用了 Bob Ippolito 的代码,即我们很喜欢的 MochiKit JavaScript 库。清单 5显示了最简单的 JSON/REST 客户机代码:
清单 5. 最简单的 JSON/REST 客户机
//
// rest.js
//
// Simplistic framework for bi-directional JSON transport via REST
//
SERVER = 'http://localhost/rest_cgi.py'
function handle_success(result){
alert('Success: ' + result.responseText);
}
function handle_error(result){
logError(result.responseText);
}
var sample_content = {'name': 'Sir Lancelot',
'quest': 'To seek the holy grail',
'favorite_color': 'blue'};
function _sendVerb(verb, content, handler){
var req = getXMLHttpRequest();
// Certain browsers don't actually support verbs besides GET
// and POST, spoiling the party for the rest of us
content['method'] = verb;
if (verb != 'GET'){
verb = 'POST'
}
req.open(verb, SERVER);
# queryString is the easiest way to send data to the server
json_content = queryString(['json_value'],
[serializeJSON(content)]);
var req = sendXMLHttpRequest(req, json_content)
req.addCallbacks(handler, handle_error);
}
function get(){
_sendVerb('GET', '', handle_success);
}
function post(){
_sendVerb('POST', sample_content, handle_success);
}
function put(){
_sendVerb('PUT', sample_content, handle_success);
}
function test_delete(){
_sendVerb('DELETE', sample_content, handle_success);
} |
JSON 和微格式
有了清单4和5的代码后就可以轻松地发送 JSON 了,但是还需要对其做点什么。从前面的讨论来看,最自然的就是将其转换回 hCalendar 或 iCalendar,这取决于是在客户端还是服务器端以及您的目标是什么。比方说,在客户端可以使用 MochiKit(特别是它提供的快捷 DOM 函数)为清单 2中的 JSON 数据创建一个简单的模版,在浏览器中将其重新格式化为 hCalendar,只要将 handleSuccess()函数替换为清单 6:
清单 6. 替换 handleSuccess() 函数
function handleSuccess(result){
var data = evalJSON(result.responseText);
// Convert json data to DOM nodes
var hCalendarData = objectToCalendar(data);
// In a real application we would add/replace this in our
// Web page somewhere, but for this demo we'll just display it.
alert(toHTML(hCalendarData));
}
var ABBR = createDOMFunc('abbr');
function pad2(number){
if (number < 10){
return '0' + number;
}else{
return '' + number;
}
}
function time(date){
return pad2(date.getHours()) +
':' +
pad2(date.getMinutes());
}
function objectToCalendar(obj){
var startDate = isoTimestamp(obj.start);
var endDate = isoTimestamp(obj.end);
var cal = DIV({'class':'vevent'},
A({'class':'url', 'href': obj.url},
ABBR({'class':'dtstart', 'title': obj.start},
startDate.toLocaleDateString(),
' - ',
time(startDate)
),
' - ',
ABBR({'class': 'dtend', 'title': obj.end},
time(endDate)
),
' - ',
SPAN({'class': 'summary'}, obj.summary),
' - at ',
SPAN({'class': 'location'}, obj.location)
),
DIV({'class':'description'},
P(obj.description)
)
);
return cal;
} |
如果清单 6中的代码做什么不够清楚,MochiKit 定义了大量的 HTML DOM 快捷函数,可以方便地创建 hCalendar 片段的 DOM 结构。虽然 元素没有内建的快捷函数,代码也创建了其中的一个。MochiKit 完成 ISO8601 格式和 JavaScript Date 对象之间的转换,但是 Date 对象内建的字符串呈现功能可能不是您希望的,因此可以编写几行代码自己处理。没有什么奇妙之处,但如果仍然不清楚,最好看一看第一手的 MochiKit 文档。
现在可以使用 AJAX 向浏览器发送 JSON 数据并使用浏览器中的模板格式化成 hCalendar 了。除了兼容一大堆时髦词之外,它完成了您可能觉得确实有用的 一些工作。
结束语
这里所述的技术对您是否有用还是归结到计算机科学中的那句老话上:视情况而定。如果建立基于 REST 的 Web 服务,那么通过 JSON 而不是 XML 传输数据可能更快更方便。如果使用 reStructured Text 来实现更简单(也更易阅读)的 HTML 内容的创建,在 HTML 形式(hCalendar)或扁平文本形式(iCalendar)中直接包含微格式可能处理起来更方便。开发新系统时,这两种技术都值得考虑。
微格式的最终目标是让数据更便于人类阅读,同时保持数据对机器解析的友好性。微格式的指导思想是尽可能重用已有的语义格式,特别是 HTML。AJAX、JSON 和 REST 都使得创建微格式系统和其他内容更方便更丰富,而轻量级标记使得为这类系统创建和编辑内容更容易、更快、更容易阅读。因此,所有这些技术都有自己的价值,将其结合在一起会形成一种增强效应。
作者简介
Dethe Dethe Elza,高级技术架构师,JustSystems
David Mertz,作家,Gnosis Software,Inc.
(责任编辑:铭铭 mingming_ky@126.com TEL:(010)68476636)
- 上一篇:探究AJAX技术神话背后的支持
- 下一篇:基于GWT轻松掌握AJAX开发(1)






