使用 Twisted 框架进行网络编程--实现 Web 服务器(2)
- UID
- 1066743
|
使用 Twisted 框架进行网络编程--实现 Web 服务器(2)
使 Weblog 变成动态页面处理 Web 日志的另一种方法是每次收到请求时使用动态页面来生成最新访问量。但是,每次接收到这样的一个请求就读取整个 access-log 文件并不是个好主意 - 忙碌的网站在日志文件中可能有几千条记录,反复读取这些记录非常耗时间。更好的办法是让 Twisted 服务器自己拥有一个针对日志文件的文件句柄,只在需要时才读取 新记录。
在某种程度上,让服务器维护文件句柄正是 tlogmaker.py 所做的工作,但是它将最新的记录存储在文件而不是存储在内存中。但是,这种方法强迫我们围绕该持久性功能编写整个服务器。让各个动态页面分别向服务器发出自己的持久性请求会更加好。例如,通过这种方法您可以添加新的有状态动态页面,而不必停止或改变长期运行的(和通用的)服务器。页面分配的持久性的关键是 Twisted 的 注册表。例如,下面是一个处理 Weblog 的动态页面:
清单 4. www/Weblog.rpy 动态 Weblog 页面
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
| from twisted.web import resource, server
from persist import Records
from webloglib import log_fields, TOP, ROW, END, COLOR
import webloglib as wll
records = registry.getComponent(Records)
if not records:
records = Records()
registry.setComponent(Records, records)
class Resource(resource.Resource):
def render(self, request):
request.write(TOP)
odd = 0
for rec in records.getNew():
print rec
hit = [field.strip('"') for field in log_fields(rec)]
if hit[wll.status]=='200' and hit[wll.referrer]!='-':
resource = hit[wll.request].split()[1]
referrer = hit[wll.referrer].replace('&',' &')
request.write(ROW % (COLOR[odd],referrer,resource))
odd = not odd
request.write(END)
request.finish()
return server.NOT_DONE_YET
resource = Resource()
|
一开始会对注册表产生的疑惑是 Weblog.rpy 从未导入它。.rpy 脚本和纯 .py 脚本不完全一样 - 前者在 Twisted 环境 中运行,该环境提供了对其中的 register 的自动访问。 request 对象是另一个来自框架而非 .rpy 自身的东西。
还请注意返回页面内容的方式,这种方式有些新鲜。上面不只返回 HTML 字符串,我们将几次针对 request 对象的写操作高速缓存起来,然后通过调用 request.finish() 来完成这些工作。模样奇特的返回值 server.NOT_DONE_YET 是一个标记,要求 Twisted 服务器将页面内容清出 request 对象。另一个选项是将 Deferred 对象添加到请求中,并在执行对 Deferred 的回调时处理页面(例如,如果直到数据库查询完成后才能生成页面)。
创建持久性对象请注意 Weblog.rpy 顶部少量的条件逻辑。第一次处理动态页面时, Records 对象还未被添加到注册表中。但是第一次之后,我们希望每次调用 records.getNew() 都使用相同的对象。如果调用 registry.getComponent() 成功,则这次调用会返回对应类的已注册对象,否则就返回一个错误值以允许进行测试。当然,调用过程之间,对象保存在 Twisted 服务器的地址空间中。
持久性类最好放在 .rpy 文件所导入的模块中。这样一来,每个动态页面都可以利用您编写的持久性类。实例属性中可以包含您喜欢的任何类型的持久性。但是,有些东西(比如开放文件)不能在服务器关闭时保存(但是,简单的值可以在服务器运行之间保存,并且可以保存在诸如 web-shutdown.tap 之类的文件中)。我使用的模块 persist 包含了一个非常简单的类 Counter ,该类借用自 Twisted Matrix 文档,还包含另一个类 Records ,我将它用于 Weblog 动态页面:
清单 5. 持久性支持模块 persist.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| class Counter:
def __init__(self):
self.value = 0
def increment(self):
self.value += 1
def getValue(self):
return self.value
class Records:
def __init__(self, log_name='../access-log'):
self.log = open(log_name)
self.recs = self.log.readlines()
def getNew(self):
self.recs.extend(self.log.readlines())
self.recs = self.recs[-35:]
return self.recs
|
您可以很自由地在持久性类中放置您喜欢的任何方法 - 注册表只是在各次对动态页面的调用之间将实例保存在内存中。
下一次在本文中,我们研究了 Twisted Web 服务器的基础。安装基本服务器(或者甚至是有少许定制代码的服务器)是非常简单的。但是 twisted.web.woven 模块中有更强大的功能,该模块为 Twisted Web 服务器提供了模板制作系统。总而言之,woven 提供了类似于 PHP、ColdFusion 或 JSP 这样的编程风格,但是可以证明,它提供的代码和模板之间的部分比其他那些系统所提供的要有用得多(当然, twisted.web.woven 允许用 Python 编写您的程序)。在本系列的第 3 部分和第 4 部分中,我们还将解决动态页面和 Web 安全性问题。 |
|
|
|
|
|