用GAE+jQuery打造无需数据库的AJAX聊天室
2009 4 22 04:08 AM 4768次查看
分类:Google App Engine 标签:Google App Engine, JavaScript, Python, jQuery
不过如果无需长期保存聊天数据的话,实际上连数据库都不需要,直接用Handler Script缓存即可。
这次我没有用XML来做,而是换成了JSON,代码一下就简单了很多。
此外我用到了自己写的一个Queue模块,详情见用Python写的限制长度的队列。你也可以直接使用list,只不过Handler Script缓存占用量会大些。
服务器端:
# -*- coding: utf-8 -*-
import os
from datetime import datetime, timedelta, tzinfo
from urllib import quote
from google.appengine.api import users
from google.appengine.ext import webapp
from google.appengine.ext.webapp.util import run_wsgi_app
from google.appengine.ext.webapp import template
from Queue import Queue
maxID = 0
messages = Queue()
class CST(tzinfo):
def utcoffset(self, dt):
return timedelta(hours=8)
def dst(self, dt):
return timedelta(0)
def tzname(self, dt):
return 'China Standard Time UT+8:00'
def newMessage(author=None, content=''):
global maxID
maxID += 1
return {
'id': maxID,
'time': datetime.now(CST()).isoformat(' '),
'author': quote(author.nickname() if author else '天朝匿名用户'),
'content': quote(content.encode('utf8'))
}
class MainPage(webapp.RequestHandler):
def get(self):
if users.get_current_user():
url = users.create_logout_url(self.request.uri)
url_linktext = '退出'
else:
url = users.create_login_url(self.request.uri)
url_linktext = '登录'
template_values = {
'url': url,
'url_linktext': url_linktext,
}
path = os.path.join(os.path.dirname(__file__), 'index.html')
self.response.out.write(template.render(path, template_values))
class Postmsg(webapp.RequestHandler):
def post(self):
messages.append(newMessage(users.get_current_user(), self.request.get('content')))
class Getmsg(webapp.RequestHandler):
def get(self):
self.response.headers['Content-Type'] = 'application/json; charset=UTF-8'
result = {}
global maxID
result['id'] = maxID
id = int(self.request.get('id'))
if maxID <= id:
self.response.out.write(result)
return
result['messages'] = sorted([message for message in messages if message['id'] > id], key=lambda message: message['id'], reverse=True)
self.response.out.write(str(result))
application = webapp.WSGIApplication([('/', MainPage),
('/getmsg', Getmsg),
('/postmsg', Postmsg)])
def main():
run_wsgi_app(application)
if __name__ == '__main__':
main()
客户端:<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>keakon的恶搞聊天室</title>
<style type="text/css">
#input { position: absolute; width: 45%; left: 50%; }
#content { width: 95%; }
#msg { position: absolute; top: 0; width: 45%; height: 100%; word-wrap: break-word; word-break: break-all; }
.top1em { margin-top: 1em }
.top2em { margin-top: 2em }
</style>
<script src="http://www.google.com/jsapi"></script>
<script type="text/javascript">
google.load("jquery", "1.3.2");
</script>
<script type="text/javascript">
var g_id = 0;
function submit() {
$.post(
"/postmsg",
{content: $("#content").val()},
function() {check_msg(); $("#content").val("");}
);
}
function check_msg() {
$.getJSON(
"/getmsg",
(function () {
if ("\v" == "v") return {id: g_id, rand: Math.random()}; // IE
else return {id: g_id};
})(),
function(json) {
if (json.id > g_id) {
var msg = [];
g_id = json.id;
$.each(json.messages, function (index, value) {
var content = decodeURIComponent(value.content).replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
msg.push("<b>");
msg.push(decodeURIComponent(value.author));
msg.push("</b> @ ");
msg.push(value.time);
msg.push(":<blockquote><pre>");
msg.push(content);
msg.push("</pre></blockquote>");
});
if (msg) {
$('#msg').prepend(msg.join(""));
}
check_msg();
}
}
);
}
$(document).ready(
function() {
check_msg();
setInterval(check_msg, 3000);
$("#content").keypress(function(e) {
if (e.shiftKey && e.keyCode == 13) submit();
});
$("#submit_msg").click(submit);
}
);
</script>
</head>
<body>
<div id="input">
<div><textarea id="content" rows="3" cols="60"></textarea></div>
<div class="top1em"><input type="submit" value="submit" id="submit_msg" />
<a href="{{url}}">{{url_linktext}}</a></div>
<div class="top2em">注意:
<blockquote><p>可以用Shift+回车键快速发送消息。</p>
<p>本站使用Google App Engine打造,点<a href="http://www.keakon.cn/bbs/thread-1130-1-1.html" style="color: red">这里</a>查看源码。</p></blockquote>
</div>
</div>
<div id="msg"></div>
</body>
</html>
代码基本上和之前差不多,不过有个地方要说下:(function () {
if ("\v" == "v") return {id: g_id, rand: Math.random()}; // IE
else return {id: g_id};
})()
实际上IE浏览器需要加个随机参数,否则第2次AJAX GET是不会产生的,浏览器默认就从缓存里取数据了,就算服务器端写了self.response.headers['Cache-Control'] = 'no-cache,must-revalidate'也没用。如果不怕影响性能,直接写{id: g_id, rand: Math.random()}也是可以的;我之所以用匿名函数,是为了不拖慢其他浏览器的速度。
向下滚动可载入更多评论,或者点这里禁止自动加载。