GAE1.4尝鲜
by
at 2010-12-05 11:20:54
original http://www.javaeye.com/topic/833763
GAE1.4发布了,带来了很多新的功能。不过我最在意的有两个:一是支持代码下载;二是支持及时通讯(channel api),现在我们来玩玩这两个东西。
1、代码下载
我们一般通过appcfg.py来上传、更新代码,但是没有下载的功能。如果换了一台机器,又看到不代码,真的很窝火。不过,现在GAE提供了,真的很方便,赞一个GAE。下载代码很简单,看一个简单的例子:
Usage: appcfg.py [options] download_app -A app_id [ -V version ] <out-dir>
C:\Users\Administrator\Desktop>appcfg.py download_app -A flyingzl -V 2 flyingzl-project D:\program\python\GAE\appcfg.py:42: DeprecationWarning: the sha module is deprec ated; use the hashlib module instead os.path.join(DIR_PATH, 'lib', 'django'), D:\program\python\GAE\google\appengine\tools\dev_appserver_login.py:33: Deprecat ionWarning: the md5 module is deprecated; use hashlib instead import md5 Server: appengine.google.com. Fetching file list... Fetching files... [1/23] chat.py [2/23] send_mail.py [3/23] hello_template.html [4/23] hello_user.py ...
2、即时通讯支持(channel API)
即时通信,即我们常说的comet,用于模拟和远程服务端长连接,常见的技术有轮询(poll)、推送(push)、websocket(html5支持,不过现在大部分服务器还不支持,GAE以后也会支持这个!)。关于后台的实现,各种各样,开源的技术也不少,我们看看google的实现
从图可以看出,在我们和GAE进行通信时,中间其实还有一个基于XMLPP的google talk,我们每次通信首先走的是google talk然后google talk再和gae进行通信。。。在之后的列子中,通过firebug的console我们可以看到加载google talk脚本的过程。
接着看图:
可以看到,在browser端,我们是和在一个看不到的iframe在通信,我们把数据传给这个隐藏的iframe,然后iframe再和google talk通信,然后再和GAE通信,貌似有点小复杂。不过没有关系,这些都是对用户透明的。说了这么多废话,直接看api,哈哈
如果大家熟悉html5的websocket,可以看到channel api的实现完全和websocket一致。
很简单吧,现在我们做一个样例,就是做一个非常简单的聊天室。有兴趣的童鞋可以好好改造下,界面如下:
3、代码实现聊天室
首先创建服务端
coding=utf-8
''' Created on 2010-12-4 @author: flyingzl ''' from google.appengine.ext import webapp from google.appengine.ext.webapp import util,template from google.appengine.api import channel from hashlib import md5 import time
class Chat(webapp.RequestHandler):
def get(self): self.response.headers['Content-Type']='text/html;charset=utf-8' key=md5('1234567890').hexdigest() client_id=channel.create_channel(key) self.response.out.write(template.render("templates/chat.html", {'channel_id':client_id}))
class ChatSender(webapp.RequestHandler): def get(self): self.response.headers['Content-Type']='text/html;charset=utf-8' self.error(500) self.response.out.write('只支持Post请求')
def post(self): key=md5('1234567890').hexdigest() message=self.request.get('message','') now=time.strftime("%Y-%m-%d %H:%M:%S") ip=self.request.environ['REMOTE_ADDR'] try: channel.send_message(key, "%s(%s)-->%s"%(ip,now,message)) except channel.InvalidChannelClientIdError: self.error(500) self.response.out.write("Channel标识符不合法") except channel.InvalidMessageError: self.error(500) self.response.out.write("发送的消息太长,最大长度不能超过")+channel.MAXIMUM_MESSAGE_LENGTH+"个字节"
def main(): app=webapp.WSGIApplication([('/chat',Chat),('/chat/sender',ChatSender)],debug=True); util.run_wsgi_app(app)
if name=='main': main()
代码比较简单,主要有两个过程,一个是创建channel,另外一个是通过channel发送消息。
再看看客户端:
<!doctype> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></meta> <title>Chat</title> <style type="text/css"> #mainDiv{ width:600px; height:400px; padding:5px; margin:10px auto; border:1px solid lightblue; }#message{ width:100%; height:370px; margin-bottom:5px; } #userMessage{ width:450px; margin-right:2px; } </style> </head> <body> <div id="mainDiv"> <textarea id='message'></textarea> <input id="userMessage" /><button id='btn' disabled onClick="sendMessage()">正在连接服务器……</button> </div> <script type="text/javascript" src="/_ah/channel/jsapi"></script> <script type="text/javascript" src="/js/jquery-1.4.2.min.js"></script> <script> var channel_id='', timeoutID=''; $(function(){ var channel=new goog.appengine.Channel(channel_id), socket=channel.open(); socket.onopen=function(){ $('#btn').html("发送").removeAttr('disabled'); } socket.onmessage=function(data){ var message=$("#message").val(); $.trim(message)?$("#message").val(message+"\n"+data.data):$("#message").val(data.data); } }); function sendMessage(message){ if(timeoutID){ alert("您发送的太快了,休息一下下……"); return; } var message=$('#userMessage').val(); if(!$.trim(message)){ alert("请输入要发送的消息!"); $('#userMessage').focus(); return; } $.ajax({ type:'POST', data:"message="+message, url:'/chat/sender', error:function(err){ alert(err.responseText); } }); $('#userMessage').val('') timeoutID=setTimeout(function(){ timeoutID=''; },500); } </script> </body>
</html>
创建channel的过程是不是和websocket很像?我们只需要监听onopen、onmessage就可以获得服务器传来的消息;不过我有点没搞明白,为什么不可以像websocket那样通过socket.send方法发送数到远程呢?或许本身gae就支持的不好。
到此,一个简单的聊天室就做好了,几行代码,就完成了一个我们之前要花费很大气力才能做完的,GAE真的是太赞了,继续关注!
代码本身很简单,我就不上传代码了。大家看明白就可以咯!祝大家周末愉快~~
-
本文附件下载:
<li><a href="http://dl.javaeye.com/topics/download/4e36b6c5-9d01-3460-b06c-b581fcd8308f">googleapis-building-real-time-apps-app-engine-feed-api.pdf</a> (821.5 KB)</li>
<br><br>
作者: <a href="http://flyingzl.javaeye.com">flyingzl</a>
<br>
声明: 本文系JavaEye网站发布的原创文章,未经作者书面许可,严禁任何网站转载本文,否则必将追究法律责任!
<br><br>
<span style="color:red">
<a href="http://www.javaeye.com/topic/833763" style="color:red">已有 <strong>0</strong> 人发表回复,猛击->><strong>这里</strong><<-参与讨论</a>
</span>
<br><br><br>
JavaEye推荐