编者注:我们发现了有趣的系列文章《30天学习30种新技术》,正在翻译,一天一篇更新,年终礼包。下面是第23天的内容。
今天的《30天学习30种新技术》,我决定暂时放下 JavaScripts 的内容,而去学习一个叫做 Tornado 的 Web 框架。我决定去学 Tornado 的原因是我这样就可以用 Python 去写 Web 程序了。我只学过 Flask 框架,所以我觉得 Tornado 应该能增加我在 Python Web 开发方面的知识。我们在这篇博文中描述的应用使用 Tornado 来作 REST 后端,MongoDB 作为数据库,AngularJS 作为客户端那边的 JavaScripts MVC 框架,然后 OpenShift 作为部署的平台。
什么是 Tornado?
Tornado 是一个开源的 Python Web 框架,是一个非阻塞(non blocking)的的 Web 服务器, 最开始是在 FriendFeed开发的。在 FriendFeed 被收购之后,Facebook 维护并继续发展 Tornado。由于它的非阻塞网络输入输出(non-blocking network I/O )特性,它有卓越的可扩展性,能同时支持一千多个连接。
应用案例
在这篇博文中,我们将会开发一个允许用户发布和分享链接的社交化书签应用。你可以在这里看到真实在 OpenShift 上运行着的程序。这是我们在 Day 22 开发过的应用,所以可以参考那篇博文以便更好地理解这个应用案例。
GitHub 仓库
今天这个演示应用的代码可以在 GitHub 上得到:day25-tornado-demo-app。
前期准备
在我们开始 Tornado 之前,我们需要在机器上安装 Python 和 virtualenv。在这篇博文中,我使用的 Python 版本是 2.7
这个应用使用 MongoDB 作为数据存储的软件,所以请下载对应你所用操作系统的最新的 MongoDB 发行版。
开发 Tornado MongoDB 应用
我们会使用 pip
安装 Tornado。对于那些不熟悉 pip
的开发者,其实 pip
就是一个 Python 的包管理器。我们可以从官网安装 pip
。打开终端,转到任何一个在文件系统上方便的目录,然后运行下面的命令:
$ mkdir getbookmarks
$ cd getbookmarks
$ virtualenv venv --python=python2.7
$ . venv/bin/activate
$ pip install tornado
$ pip install pymongo
上面的命令会在本机上创建一个 getbookmarks 目录,然后在 Python 2.7 下激活 virtualenv,然后安装 tornado 包,最后安装 pymongo。其中,pymongo 是官方 MongoDB 的 Python 驱动;我们会使用它往 MongoDB 中写入故事(stories)。
在 getbookmarks 目录下,创建一个名为 getbookmarks.py 的文件:
$ touch getbookmarks.py
复制下面的代码,然后粘贴到 getbookmarks.py 源文件中:
import os
from tornado import ioloop,web
from pymongo import MongoClient
import json
from bson import json_util
from bson.objectid import ObjectId
class IndexHandler(web.RequestHandler):
def get(self):
self.write("Hello World!!")
settings = {
"template_path": os.path.join(os.path.dirname(__file__), "templates"),
"static_path": os.path.join(os.path.dirname(__file__), "static"),
"debug" : True
}
application = web.Application([
(r'/', IndexHandler),
(r'/index', IndexHandler),
],**settings)
if __name__ == "__main__":
application.listen(8888)
ioloop.IOLoop.instance().start()
上面的代码会执行下面的事情:
1. 我们从导入需要的库开始;
2. 下一步,我们定义一个扩展类 web.RequestHandler 的新类:IndexHandler。一个 Tornado web 应用会把 URLs 或者 URL 模式对应到 web.RequestHandler 的子类。这些类定义了 get()
、post()
等方法去处理访问这个 URL 的 HTTP GET 或者 POST 请求。当在地址 '/' 下收到一个 GET 请求时,IndexHandler 会返回一个 "Hello World!!"
3. 接着我们定义了一些应用的设置。template_path
设置是告诉 Tornado 应用在 template
目录寻找应用模板。static_path
设置告诉应用使用 static
目录里面的类似 css、图像、javascript 文件等静态文件。通过设置 debug
为 True
,你对项目做了改变后,会自动重载,不用重启查看效果。我们会在应用开发过程中,保持着调试器在后台运行。这能提供高效的开发环境。
4. 接着,我们创建一个Tornado 应用实例,把路由routes)和 settings
传递进去。
5. 最后,我们使用 python getbookmarks.py
命令启动服务器去运行这个应用
打开 http://localhost:8888 和 http://localhost:8888/index 看看是否看到 "Hello World!!"
配置 MongoDB
在导入库之后,增加下面的语句:
MONGODB_DB_URL = os.environ.get('OPENSHIFT_MONGODB_DB_URL') if os.environ.get('OPENSHIFT_MONGODB_DB_URL') else 'mongodb://localhost:27017/'
MONGODB_DB_NAME = os.environ.get('OPENSHIFT_APP_NAME') if os.environ.get('OPENSHIFT_APP_NAME') else 'getbookmarks'
client = MongoClient(MONGODB_DB_URL)
db = client[MONGODB_DB_NAME]
我们定义了 MongoDB 连接的路由和数据库的名称。如果应用是部署到 OpenShift 上,那么 OpenShift 特定环境变量会先被使用,如果没有,就会使用本机上的配置。
我们创建了一个 MongoClient 实例,把连接的路由传递进去。这个连接路由是只想运行着的 mongod 实例。接着我们使用 MongoClient 实例使用数据库
创建和列出所有的故事(Stories)
现在我们要添加创建新的故事(stories)和列出所有故事(stories)的功能。我们首先把路由加到下面的应用实例中:
application = web.Application([
(r'/', IndexHandler),
(r'/index', IndexHandler),
(r'/api/v1/stories',StoriesHandler),
],**settings)
接着,我们定义一个把故事(stories)保存在 MongoDB 和在里面查找所有故事(stories)的 StoriesHandler:
class StoriesHandler(web.RequestHandler):
def get(self):
stories = db.stories.find()
self.set_header("Content-Type", "application/json")
self.write(json.dumps(list(stories),default=json_util.default))
def post(self):
story_data = json.loads(self.request.body)
story_id = db.stories.insert(story_data)
print('story created with id ' + str(story_id))
self.set_header("Content-Type", "application/json")
self.set_status(201)
在上面的代码中:
1. 当一个用户发出一个 GET 请求到 /api/v1/stories
时,我们会向 MongoDB 中发出一个 Find() 方法请求。由于我们没有具体声明是任何查询,所以它会从 MongoDB 取出所有的故事。我们把内容类型(content type)设置为 application/json
,然后转出(dump) json 回应。
2. 当用户发出一个 POST 请求到 /api/v1/stories
,然后我们首先解码 json 的内容到一个字典(dictionary),然后把数据写入 MongoDB。我们会把回应状态(response status)设为 201(已创建)。
查看单独的故事(story)
最后一个后端功能是查看单独的故事,我们首先指明路由:
application = web.Application([
(r'/', IndexHandler),
(r'/index', IndexHandler),
(r'/api/v1/stories',StoriesHandler),
(r'/api/v1/stories/(.*)', StoryHandler)
],**settings)
我们编写 StoryHandler
class StoryHandler(web.RequestHandler):
def get(self , story_id):
story = db.stories.find_one({"_id":ObjectId(str(story_id))})
self.set_header("Content-Type", "application/json")
self.write(json.dumps((story),default=json_util.default))
上面的代码查找对应 story_id
的故事,然后转出 json 回应。
AngualarJS 前端
我决定重用我在 第 22 天 写的前端。第 22 天的内容展示了如何以 Java Spring 框架作为后端去使用 AngularJS。使用 JavaScripts MVC 架构的最好的地方就是你可以重用前端的代码,如果你的应用符合 REST 接口客户端的要求。可以阅读第 22 天的内容了解更多。
你可以在我的 GiHub 仓库下载 AngularJS 前端。复制静态文件和模板文件夹,粘贴到 getbookmarks.py 所在文件夹。
部署应用到 OpenShift
在构建应用之前,我们需要做些设置:
-
注册一个OpenShift账号。注册是完全免费的,Red Hat给每个用户三枚免费的Gear,可以用Gear运行你的应用。在写作此文的时候,每个用户能免费使用总共 1.5 GB 内存和 3 GB 硬盘空间。
-
安装 rhc客户端工具。
rhc
是ruby gem,因此你的机子上需要装有 ruby 1.8.7以上版本。 只需输入sudo gem install rhc
即可安装 rhc 。如果你已经安装过了,确保是最新版。运行sudo gem update rhc
即可升级。关于配置rhc命令行工具的详细信息,请参考: https://openshift.redhat.com/community/developers/rhc-client-tools-install
- 使用 rhc 的 setup 命令配置你的 OpenShift 账号。这个命令会帮助你创建一个命名空间,同时将你的ssh公钥上传至 OpenShift 服务器。
部署应用
输入如下命令即可将应用部署到 OpenShift:
$ rhc create-app day25demo python-2.7 mongodb-2 --from-code https://github.com/shekhargulati/day25-tornado-demo-app.git
这个命令将创建应用,设置公开的DNS,创建私有git仓库,最后利用你的Github仓库中的代码来部署应用。应用可以通过 http://day25demo-shekhargulati.rhcloud.com/#/ 访问。