设为首页 收藏本站
查看: 484|回复: 0

[经验分享] Google App Engine ProtoRPC Python API 概述

[复制链接]
累计签到:1 天
连续签到:1 天
发表于 2017-5-2 10:48:36 | 显示全部楼层 |阅读模式
  赖勇浩(http://laiyonghoa.com)
  注:前几天 GAE SDK 1.5.1 发布,其中一个新特性是 Python SDK 增加了 ProtoRPC API,我对 GAE 兴趣不大,但最近正好自己也在写基于 google protobuf 的 RPC(不同的是我的 RPC 基于 TCP 的),所以很有兴趣地看了一下 ProtoRPC 的 overview,后来心血来潮就把它简单译了一下,不过不是逐句对译,所以如有困惑,敬请参详原文(原文也在变化之中,我译的是 2011 年 6 月 25 日的版本,如果后来更新了,对不上号,概不负责):http://code.google.com/appengine/docs/python/tools/protorpc/overview.html
  ProtoRPC 发送和接收基于 HTTP 的远程过程调用(RPC)服务的简单方案。所谓 RPC 服务就是提供结构化地扩展应用程序与 Web 应用交互的一堆消息类型和远程方法。因为只能够用 Python 编程语言来定义消息和服务,所以更容易开发服务、测试服务和在 App Engine 上获得更好的伸缩性。
当把 ProtoRPC 用以任何基于 HTTP 的 RPC 时,一些常见的应用场景包括:

  • 发布第三方使用的 web APIs
  • 创建结构化的 Ajax 后端
  • 克隆长期运行的服务器交互
  可以在单一 Python 类中定义任意数量的 ProtoRPC 远程方法,每个远程方法接受一个请求(包含一些特定的参数集合),并返回一个特定的响应。所有的请求和响应都是用户定义的类,这些类又称为消息。
实验性的!
  ProtoRPC 是一个实验性的、全新的、快速变化的 App Engine 的新特性,请勿用于商业关键的应用程序,当它完全可用时,我们会告诉大家的。
ProtoRPC 的 Hello World
  这个小节演示一下从远端接受一个消息(包含了用户名 HelloRequest.my_name),并返回一个响应(HelloResponse.hello)。
from google.appengine.ext import webappfrom google.appengine.ext.webapp import utilfrom protorpc import messagesfrom protorpc.webapp import service_handlersfrom protorpc import remotepackage = 'hello'# Create the request string containing the user's nameclass HelloRequest(messages.Message):my_name = messages.StringField(1, required=True)# Create the response stringclass HelloResponse(messages.Message):hello = messages.StringField(1, required=True)# Create the RPC service to exchange messagesclass HelloService(remote.Service):@remote.remote(HelloRequest, HelloResponse)def hello(self, request):return HelloResponse(hello='Hello there, %s!' %request.my_name)# Map the RPC service and path (/hello)service_mappings = service_handlers.service_mapping([('/hello', HelloService),])# Apply the service mappings to Webappapplication = webapp.WSGIApplication(service_mappings)def main():util.run_wsgi_app(application)if __name__ == '__main__':main()
开始 ProtoRPC 之旅
  在这里我们使用 App Engine Getting Started Guide (Python) 的留言板示例(http://code.google.com/appengine/docs/python/gettingstarted/)。用户可以在线访问这个留言板(已经包含在 Python SDK 中),编写留言,查看所有用户的留言。
接下来将把 ProtoRPC 应用到这个基本的留言板中,使得 Web 应用能够存取其数据。但这个教程只涵盖了使用 ProtoRPC 来扩展留言板功能,其实你可以做到更多,比如编写一个工具读取用户提交的所有消息或创建一个每天有多少条留言的图表。根据特定的应用,可以随意使用 ProtoRPC,重要的是 ProtoRPC 可以让你随便折腾你的数据。
万事之始,是创建一个名为 postservice.py 的文件,所有存取留言板应用数据的远程方法都在其中实现。
创建 PostService 模块
  第一步,在应用程序目录下创建一个名为 postservice.py 的文件,它将实现两个方法:一个用以远程提交数据,另一个用以远程获取数据。
燃烧吧,消息!
  消息是 ProtoRPC 的基本数据类型,通过声明一个 Message 继承下来的子类来定义消息,然后定义与消息字段相应的类属性。
留言板服务能够让用户提交一个留言,那么就定义一个消息来表示一个留言吧:
from protorpc import messagesclass Note(messages.Message):text = messages.StringField(1, required=True)when = messages.IntegerField(2)
Note 消息定义了两个字段,text 和 when。每一个字段都有自己的类型,比如 text 字段的类型提 unicode 字符串,用以表示用户通过留言板页面提交的内容,而 when 字段就是一个整数,用以表示用户提交的时间戳。除此之外:

  • 每个字段有一个唯一的数值(如 text 是 1,when 是 2),这是底层网络协议要用到的字段标识
  • 定义 text 为必填字段。每个字段默认是可选的,所以要用 required=True 来定制为必填字段。
  可以通过 Note 类的构建函数来给字段赋值:
# Import the standard time Python library to handle the timestamp.import timenote_instance = Note(text=u'Hello guestbook!', when=int(time.time())
也可以操作普通的 Python 属性一样读、写字段,比如下面的代码可以改变消息:
print note_instance.textnote_instance.text = u'Good-bye guestbook!'print note_instance.text# Which outputs the following>>>Hello guestbook!Good-bye guestbook!
定义服务
  一个服务就是指一个从 Service 基类继承的类,服务的远程方法由 remote 装饰器标识。服务的每个方法都接受单个消息作为参数,并返回一个消息作为响应。
现在来定义 PostService 的第一个方法。如果你还没有准备好,记得先在你应用目录下创建 postservice.py 文件,或如果你觉得有必要的话就读一下留言板教程(http://code.google.com/appengine/docs/python/gettingstarted/)。PostService 与留言板教程一样,使用 guestbook.Greeting 来存储提交的数据。
import datetimefrom protorpc import message_typesfrom protorpc import remoteimport guestbookclass PostService(remote.Service):# Add the remote decorator to indicate the service methods@remote.remote(Note, message_types.VoidMessage)def post_note(self, request):# If the Note instance has a timestamp, use that timestampif request.when is not None:when = datetime.datetime.utcfromtimestamp(request.when)# Else use the current timeelse:when = datetime.datetime.now()note = guestbook.Greeting(content=request.text, date=when)note.put()return message_types.VoidMessage()
remote 装饰器有两个参数:

  • 请求类型,post_note() 接受一个 Note 实例作为请求
  • 响应类型,ProtoRPC 有一个内建类型叫人 VoidMessage(在 protorpc.message_types 模块中定义),它表示没有字段的消息,所以 post_note() 其实并没有返回任何有意义的东西给调用方。
  因为 Note.when 是一个可选字段,所以调用方可能并没有对它赋值,这时 when 的值就是 None,当 Note.when 的值为 None,post_note() 以接收到消息的时间作为时间戳。
响应消息由远程方法实例化,一般是远程方法需要返回的时候会这样做。
注册服务
  可以使用 App Engine 的 webapp 框架(http://code.google.com/appengine/docs/python/tools/webapp/)发布新的服务。ProtoRPC 有一个很小的库(protorpc.service_handlers)可以简化这个事儿。在应用目录新建一个 services.py 的文件,把下面的代码拷进去:
from google.appengine.ext import webappfrom google.appengine.ext.webapp import utilfrom protorpc import service_handlersimport PostService# Register mapping with application.application = webapp.WSGIApplication(service_handlers.service_mapping([('/PostService', PostService.PostService)]),debug=True)def main():util.run_wsgi_app(application)if __name__ == '__main__':main()
然后把下面的代码加到 app.yaml 文件中:
- url: /PostService.*script: services.py
可以创建你的基本 webapp 的服务啦~
通过命令行测试服务
  创建服务后,可以使用 curl 或相似的命令行工具进行测试:
# After starting the development web server:% curl -H /'content-type:application/json' /-d {"text": "Hello guestbook!"}'/http://localhost:8080/PostService.post_note
当返回一个空的 JSON 表示留言提交成功,可以通过浏览器(http://localhost:8080/)查看这个留言。
增加消息字段
  现在可以向 PostService 提交留言了,接下来再增加一个新的方法。先在 postservice.py 中定义一个请求消息,它有一些默认值,还有之前没有接触过的枚举字段(用来告诉服务器如何对留言排序)。让我们把下面的代码加到 PostService 类之前:
class GetNotesRequest(messages.Message):limit = messages.IntegerField(1, default=10)on_or_before = messages.IntegerField(2)class Order(messages.Enum):WHEN = 1TEXT = 2order = messages.EnumField(Order, 3, default=Order.WHEN)
消息中 limit 字段表示最大的请求的留言数量,默认为 10 条(通过 default=10 关键字参数指定)。
order 字段引入了一个 EnumField 类,它能够让 enum 字段类型的取值严格地限定在已定义的符号值范围内。在这里,服务器如何排序显示中的留言是由 order 字段指定的。要定义枚举值,需要创建 Enum 类的子类,它的每一个类属性都应为唯一的数字,然后被转换为一个可以通过类来存取的枚举类型的实例。
print 'Enum value Order.%s has number %d' % (Order.WHEN.name,Order.WHEN.number)
除了访问它的 name 和 number 属性,enum 值还有一个“特殊技能”能够更方便地转换它的 name 和 number,比如转换某个值到字符串或整数:
print 'Enum value Order.%s has number %d' % (Order.WHEN,Order.WHEN)
枚举字段的声明与其它字段是类似的,除了需要在第一个参数标明它的枚举类型,而且枚举字段也可以有默认值。
定义响应消息
  现在定义一下 get_notes() 的响应消息。这个响应显然应该包含一组 Note 消息,消息能够包含其它的消:
class Notes(messages.Message):notes = messages.MessageField(Note, 1, repeated=True)
Notes.notes 字段是一个重复字段(通过 repeated=True 关键字参数说明),重复字段的值是一个列表,在这个例子里,Notes.notes 就是包含多个 Note 实例的列表,列表是自动创建的,并且不能赋值为 None。
来个如何创建 Notes 对象的例子:
response = Notes(notes=[Note(text='This is note 1'),Note(text='This is note 2')])print 'The first note is:', response.notes[0].textprint 'The second note is:', response.notes[1].text
实现 get_notes
  现在把 get_notes() 方法加到 PostService 类中:
import datetimefrom protorpc import remoteclass PostService(remote.Service):...@remote.remote(GetNotesRequest, Notes)def get_notes(self, request):query = guestbook.Greeting.all().order('-date')if request.on_or_before:when = datetime.datetime.utcfromtimestamp(request.on_or_before)query.filter('date <=', when)notes = []for note_model in query.fetch(request.limit):if note_model.date:when = int(time.mktime(note_model.date.utctimetuple()))else:when = Nonenote = Note(text=note_model.content, when=when)notes.append(note)if request.order == GetNotesRequest.Order.TEXT:notes.sort(key=lambda note: note.text)return Notes(notes=notes)

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-372032-1-1.html 上篇帖子: Python中的文件和目录操作 下篇帖子: perl,python和ruby的对比
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表