Twisted网络编程必备(5)

来源:互联网 发布:如何购买阿里云空间 编辑:程序博客网 时间:2024/05/16 17:56


转自:http://www.yybug.com/read-htm-tid-15324.html

4.4 管理资源等级

 

WEB应用中的路径通常使用分级目录管理。例如如下URL:

http://example.com/people

http://example.com/people/charles

http://example.com/people/charles/contact

这里可以很清楚的看出等级划分。页面/people/charles是/people的子页面,而页面/people/charles/contact是/people/charles的子页面。等级中的每个页面都有特定的意义:/people/charles是一个人,而/people/charles/contact是一项数据,charles的数据。

WEB服务器的缺省行为是将PATH等级映射到磁盘上的文件。客户端的每次请求都是对应特定的资源,服务器查找文件并定位磁盘路径,然后将文件内容或者可执行文件的执行结果作为响应。在WEB应用中可以人为的生成一个对应路径文件的内容。例如,你的数据并没有存储在磁盘上,而是在一个关系数据库或者另一个服务器上。或者你想要在请求时自动创建资源。类似这种情况,最好的办法是为等级浏览创建自己的逻辑。

编写自己的资源管理逻辑可以帮助你管理安全。而不是打开WEB服务器的整个目录,你可以有选择的控制哪些文件是可以访问的。

 

4.4.1 下面如何做?

 

twisted.web.resource和twisted.web.static还有twisted.web.server模块提供了比twisted.web.http.Resource更高层次的请求管理类,你可以使用这些来设置一个WEB服务器来处理多种逻辑等级的资源。例子4-4使用了这些类来建立十六进制颜色代码。请求资源/color/hex,hex是十六进制的颜色代码,你可以得到一个背景为#hex的页面。对应每一种可能出现的颜色可能,服务器动态创建资源。

复制代码
代码
from twisted.web import resource,static,serverclass ColorPage(resource.Resource): def __init__(self,color): self.color=color def render(self,request): return """ <html> <head> <title>Color: %s</title> <link type='text/css' href='/styles.css' rel='Stylesheet' /> </head> <body style='background-color: #%s'> <h1>This is #%s.</h1> <p style='background-color: white'> <a href='/color/'>Back</a> </p> </body> </html> """ % (self.color, self.color, self.color)class ColorRoot(resource.Resource): def __init__(self): resource.Resource.__init__(self) self.requestedColors=[] self.putChild('',ColorIndexPage(self.requestColors)) def render(self,request): # redirect /color -> /color/ request.redirect(request.path+'/') return 'please use /colors/ instead.' def getChild(self,path,request): if path not in self.requestedColors: self.requestedColors.append(path) return ColorPage(path)class ColorIndexPage(resource.Resource): def __init__(self,requestColorsList): resource.Resource.__init__(self) self.requestedColors=requestedColorsList def render(self,request): request.write(""" <html> <head> <title>Colors</title> <link type='text/css' href='/styles.css' rel='Stylesheet' /> </head> <body> <h1>Colors</h1> To see a color, enter a url like <a href='/color/ff0000'>/color/ff0000</a>. <br /> Colors viewed so far: <ul>""") for color in self.requestedColors: request.write( "<li><a href="/blog/%s" style='color: #%s'>%s</a></li>" % ( color, color, color)) request.write(""" </ul> </body> </html> """) return ""class HomePage(resource.Resource): def render(self,request): return """ <html> <head> <title>Colors</title> <link type='text/css' href='/styles.css' rel='Stylesheet' /> </head> <body> <h1>Colors Demo</h1> What's here: <ul> <li><a href='/color'>Color viewer</a></li> </ul> </body> </html> """if __name__=='__main__': from twisted.internet import reactor root=resource.Resource() root.putChild('',HomePage()) root.putChild('color',ColorRoot()) root.putChild('styles.css',static.File('styles.css')) site=server.Site(root) reactor.listenTCP(8000,site) reactor.run()
复制代码

 

例子4-4引用了静态文件。所以需要在resourcetree.py脚本目录下创建一个styles.css文件。内容如下:

复制代码
代码
body { font-family: Georgia, Times, serif; font-size: 11pt;}h1 { margin: 10px 0; padding: 5px; background-color: black; color: white;}a { font-family: monospace;}p { padding: 10px;}
复制代码

 

运行resourcetree.py脚本,将会在8000端口启动一个WEB服务器。下面是服务器全部可用路径:

/        主页

/css    虚拟的CSS资源

/css/styles.css    静态文件styles.css

/colors/ 颜色查看页面

/colors/hexcolor 按照背景色为#hexcolor的页面

尝试通过http://localhost:8000/colors/00abef来访问,将会得到背景色为#00abef的页面,大约是亮蓝色。

可以随便试试其他颜色。同样可以进入http://localhost:8000/,选择可选答案。

4.4.2 它们如何工作?

 

例子4.4从twisted.web包中引入了几个类:resource.Resource、static.File、server.Site。每个resource.Resource对象做两件事。首先,定义请求的资源如何处理。第二,定义请求子资源的Resource对象。

例如查看类ColorRoot。在这个类的实例稍后被加入了/colors这个等级资源。初始化时,ColorRoot使用putChild方法插入ColorIndexPage这个资源座位''资源。这意味着所有对/colors/的请求都由ColorIndexPage对象来处理。

你可以把他们想象为等价的,但是/stuff和/stuff/是不同的。浏览器在解释相对路径时,对是否加上斜线的处理方法是不同的。在第一个例子中,对"otherpage"的请求会解释为"http://example.com/otherpage",在第二个例子中解释为"http://example.com/stuff/otherpage"。

如果你不清楚(explicit)服务器代码,这个问题可能会再次郁闷你。最好是预先设计好是否需要在URI末尾加上斜线,并重定向请求。Resource类将会简化这些操作。如果设置了addSlash属性为True,一个Resource会自动在找不到对应资源时自动在URL末尾添加斜线来再次查找。

4.4 管理资源等级

 

4.6 运行HTTP代理服务器

 

除了HTTP服务器和客户端以外,twisted.web还包含了HTTP代理服务器的支持。一个代理服务器是一个服务器和一个客户端。他接受来自客户端的请求(作为服务器)并将他们转发到服务器(作为客户端)。然后将响应发送回客户端。HTTP代理服务器可以提供很多有用的服务:缓存、过滤和使用情况报告。下面的例子展示了如何使用Twisted构建一个HTTP代理服务器。

 

4.6.1 下面如何做?

 

twisted.web包包含了twisted.web.proxy,这个模块包含了HTTP代理服务器。例子4-7构建了一个简单的代理服务器。

 

复制代码
代码
from twisted.web import proxy,httpfrom twisted.internet import reactorfrom twisted.python import logimport syslog.startLogging(sys.stdout)class ProxyFactory(http.HTTPFactory): protocol=proxy.Proxyreactor.listenTCP(8001,ProxyFactory())reactor.run()
复制代码

 

运行simpleproxy.py脚本将会在8001端口启动代理服务器。在浏览器中设置这个代理服务器可以作为代理进行测试。对log.startLogging的调用将会把HTTP日志信息记录在stdout中,并可以直接查看。

 

$ python simpleproxy.py

2005/06/13 00:22 EDT [-] Log opened.

2005/06/13 00:22 EDT [-] __main__.ProxyFactory starting on 8001

... ...

 

这虽然给出了一个代理服务器,但是实际上没什么用处。例子4-8提供了更多的功能,可以跟踪最常使用的网页。

 

代码

 

运行wordcountproxy.py将浏览器的代理服务器设置到8001端口。浏览其他站点,或者访问http://localhost:8000/,将可以看到访问过的站点的单词频率。

 

4.6.2 它是如何工作的?

 

在例子4-8中有很多个类,但大多数是连接用的。只有很少的几个做实际工作。最开始的两个类WordParser和WordCounter,用于从HTML文档中解出单词符号并计算频率。第三个类WordCountProxy客户端包含了查找HTML文档并调用WordParser的任务。

因为代理服务器同时作为客户端和服务器,所以需要使用大量的类。有一个ProxyClientFactory和ProxyClient,提供了Factory/Protocol对来支持客户端连接。为了响应客户端的连接,需要使用ProxyRequest,它是HTTPFactory的子类,还有Proxy,是http.HTTPChannel的子类。它们对建立一个普通的HTTP服务器是有必要的:HTTPFactory使用Proxy作它的协议(Protocol),而代理Proxy HTTPChannel使用ProxyRequest作为它的RequestFactory。如下是客户端发送请求的事件处理流程:

·客户端建立到代理服务器的连接。这个连接被HTTPFactory所处理。

·HTTPFactory.buildProtocol会创建一个Proxy对象用来对客户端发送和接收数据。

·当客户端发送请求时,Proxy创建ProxyRequest来处理。

·ProxyRequest查找客户端请求的服务器。并创建ProxyClientFactory并调用reactor.connectTCP来通过factory连接服务器。

·一旦ProxyClientFactory连接到服务器,就会创建ProxyClient这个Protocol对象来发送和接收数据。

·ProxyClient发送原始请求。作为响应,它将客户端发来的请求发送给服务器。这是通过调用self.father.transport.write实现的。self.father是一个Proxy对象,正在管理着客户端连接对象。

这是一大串类,但实际上是分工明确的将工作由一个类传递到另一个类。但这是很重要的。为代理模块的每一个类提供一个子类,你可以完成每一步的控制。

整个例子4-8中最重要的一个技巧。ProxyClientFactory类有一个buildProtocol方法,可以包装好,供ProxyClient作为Protocol。它并不提供任何简单的方法来提供你自己的ProxyClient子类。解决办法是使用Python的__class__属性来替换升级ProxyClient对象来放回ProxyClientFactory.buildProtocol,这些将ProxyClient改变为WordCountProxyClient。

作为代理服务器的附加功能。例子4-8提供了标准的WEB服务器,在8000端口,可以显示从代理服务器来的当前单词统计数量。由此可见,在你的应用中包含一个内嵌的HTTP服务器是多么的方便,这种方式可以很好的提供给远程来显示相关状态信息。

0 0