GAE1.4尝鲜

2010-12-05 19:20

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[&#39;Content-Type&#39;]=&#39;text/html;charset=utf-8&#39;
    key=md5(&#39;1234567890&#39;).hexdigest()
    client_id=channel.create_channel(key)
    self.response.out.write(template.render(&quot;templates/chat.html&quot;, {&#39;channel_id&#39;: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(&#39;1234567890&#39;).hexdigest()
    message=self.request.get(&#39;message&#39;,&#39;&#39;)
    now=time.strftime(&quot;%Y-%m-%d %H:%M:%S&quot;)
    ip=self.request.environ[&#39;REMOTE_ADDR&#39;]
    try:
        channel.send_message(key, &quot;%s(%s)--&gt;%s&quot;%(ip,now,message))
    except channel.InvalidChannelClientIdError:
        self.error(500)
        self.response.out.write(&quot;Channel标识符不合法&quot;)
    except channel.InvalidMessageError:
        self.error(500)
        self.response.out.write(&quot;发送的消息太长,最大长度不能超过&quot;)+channel.MAXIMUM_MESSAGE_LENGTH+&quot;个字节&quot;

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;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    &lt;div id=&quot;mainDiv&quot;&gt;
        &lt;textarea id=&#39;message&#39;&gt;&lt;/textarea&gt;
        &lt;input id=&quot;userMessage&quot;  /&gt;&lt;button id=&#39;btn&#39; disabled onClick=&quot;sendMessage()&quot;&gt;正在连接服务器……&lt;/button&gt;
    &lt;/div&gt;
    &lt;script type=&quot;text/javascript&quot; src=&quot;/_ah/channel/jsapi&quot;&gt;&lt;/script&gt;
    &lt;script type=&quot;text/javascript&quot; src=&quot;/js/jquery-1.4.2.min.js&quot;&gt;&lt;/script&gt;
    &lt;script&gt;
        var channel_id=&#39;&#39;,
            timeoutID=&#39;&#39;;
        $(function(){
            var channel=new goog.appengine.Channel(channel_id),
                socket=channel.open();
            socket.onopen=function(){
                $(&#39;#btn&#39;).html(&quot;发送&quot;).removeAttr(&#39;disabled&#39;);
            }

            socket.onmessage=function(data){
                var message=$(&quot;#message&quot;).val();
                $.trim(message)?$(&quot;#message&quot;).val(message+&quot;\n&quot;+data.data):$(&quot;#message&quot;).val(data.data);
            }

        });

        function sendMessage(message){
            if(timeoutID){
                alert(&quot;您发送的太快了,休息一下下……&quot;);
                return;
            }
            var message=$(&#39;#userMessage&#39;).val();
            if(!$.trim(message)){
                alert(&quot;请输入要发送的消息!&quot;);
                $(&#39;#userMessage&#39;).focus();
                return;
            }
            $.ajax({
                type:&#39;POST&#39;,
                data:&quot;message=&quot;+message,
                url:&#39;/chat/sender&#39;,
                error:function(err){
                    alert(err.responseText);
                }
            });
            $(&#39;#userMessage&#39;).val(&#39;&#39;)
            timeoutID=setTimeout(function(){
                timeoutID=&#39;&#39;;
            },500);
        }

    &lt;/script&gt;
&lt;/body&gt;

</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> 人发表回复,猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
      </span>
      <br><br><br>

JavaEye推荐