写twisted.web.http.Request的子类并重载process方法来处理当前请求。Request对象已经包含了process需要调用的HTTP请求所有信息,所以只需要决定如何响应。例子4-2展示了如何运行基于http.Request的HTTP服务器。 from twisted.web import http class MyRequestHandler(http.Request): pages={ '/':'
Home
Home Page', '/test':'
Test
Test Page', } def process(self): if self.pages.has_key(self.path): self.write(self.pages[self.path]) else: self.setResponseCode(http.NOT_FOUND) self.write("
Not Found
Sorry, no such page.") self.finish() class MyHttp(http.HTTPChannel): requestFactory=MyRequestHandler class MyHttpFactory(http.HTTPFactory): protocol=MyHttp if __name__=='__main__': from twisted.internet import reactor reactor.listenTCP(8000,MyHttpFactory()) reactor.run() #by gashero 运行requesthandler.py将会在8000端口启动一个WEB服务器。可以同时阅览主页()和测试页/test()。如果你指定了想要访问其他页面,将会得到错误信息。
写一个函数来处理Request对象并产生响应。设置字典来映射每一个可用路径到WEB站点来让函数出路路径请求。使用Request.args字典存取提交的HTML表单数据。例子4-3展示了生成单页HTML表单的WEB服务器,另一个页面是通过表单数据显示的。 from twisted.web import http def renderHomePage(request): colors='red','blue','green' flavors='vanilla','chocolate','strawberry','coffee' request.write("""
Form Test
""") request.finish() def handlePost(request): request.write(""" Posted Form Datagg
Form Data
""") for key,values in request.args.items(): request.write("
%s
"%key) request.write("
") for value in values: request.write("
%s
"%value) request.write("
") request.write("""
""") request.finish() class FunctionHandleRequest(http.Request): pageHandlers={ '/':renderHomePage, '/posthandler':handlePost, } def process(self): self.setHeader("Content-Type","text/html") if self.pageHandlers.has_key(self.path): handler=self.pageHandlers[self.path] handler(self) else: self.setResponseCode(http.NOT_FOUND) self.write("
Not Found
Sorry, no such page.") self.finish() class MyHttp(http.HTTPChannel): requestFactory=FunctionHandledRequest class MyHttpFactory(http.HTTPFactory): protocol=MyHttp if __name__=='__main__': from twisted.internet import reactor reactor.listenTCP(8000,MyHttpFactory()) reactor.run() 运行formhandler.py脚本。将会在8000端口运行WEB服务器。进入可以找到表单主页。按照如下填写一些字段信息。 然后点击提交按钮,你的浏览器将会发送表单数据到页面formhandler使用HTTP的POST请求。当它接受到表单数据时,formhandler回展示提交过的字段和值。
4.3.2 它们是如何工作的?
例子4-3定义了两个函数来处理请求,renderHomePage和handlePost。FunctionHandleRequest是Request的子类,其属性pageHandler定义了路径映射功能。process方法查找路径,并尝试在pageHandlers中匹配路径。如果匹配成功,则FunctionHandleRequest传递自身到匹配函数,并且由对方负责处理;如果匹配失败,则返回404 Not Found响应。 renderHomePage函数设置处理器到/,站点的根路径。它生成的HTML表单将会提交数据到页面/formhandler。这个处理器函数/formhandler是handlePost,将会响应页面列表并提交数据。handlePost遍历值Request.args,这个字典属性包含了请求提交的所有数据。 Tip:在这种情况下,发送的表单数据在HTTP POST请求的主体中。当请求发送HTTP GET时,Request.args将会包含所有提交的URI查询字段值。你可以修改这个行为,通过改变表单生成器renderHomePage的method属性,从POST到GET,重启服务器,就可以重新提交表单。 一个HTML表单可以有多个字段具有相同的名字。例如,表单4-3中允许选中多个复选框,所有的名字都是flavor。不像很多其他的框架,http.Request并不对你隐藏什么:代替了映射字段名到字符串,Request.args映射每个字段值到列表。如果你知道要取哪一个值,那么可以只获取列表的第一个值。
Twisted提供了SQL库在twisted.enterprise包。tiwsted.enterprise包并不是真正的包含SQL驱动;它只是提供一些数据库支持中可能(potentially)会遇到的问题。当然,twisted.enterprise提供了异步的API来代替Python数据库接口模块。如果需要,它将会使用线程来防止(prevent)数据库查询的阻塞。你可以使用twisted.enterprise来使用SQL数据库,只要(as long as)你拥有一个DB-API兼容(compatible)的数据库模块即可。
首先确保你所使用的数据库模块是Python DB-API兼容的。然后创建一个twisted.enterprise.adbapi.ConnectionPool对象来引用你的数据库驱动和连接信息。下面的例子4-6使用了MySQLdb模块来连接到( by gashero)MySQL数据库。这将会运行一个很小的weblog应用并存储提交的信息。
from twisted.web import resource,static,server,http from twisted.enterprise import adbapi,util as dbutil
class RootResource(resource.Resource): def __init__(self,dbConnection): resource.Resource.__init__(self) self.putChild('',HomePage(dbConnection)) self.putChild('new',NewPage()) self.putChild('save',SavePage(dbConnection))
if __name__=="__main__": from twisted.internet import reactor dbConnection=adbapi.ConnectionPool(DB_DRIVER,**DB_ARGS) f=server.Site(RootResource(dbConnection)) reactor.listenTCP(8000,f) reactor.run()
例子4-6的代码会调用一个SQL表格叫做posts。可以按照如下SQL语句来创建这个表格:
CREATE TABLE posts( post_id int NOT NULL auto_increment, title varchar(255) NOT NULL, body text, PRIMARY KEY (post_id) );
from twisted.web import proxy,http from twisted.internet import reactor from twisted.python import log import sys log.startLogging(sys.stdout) class ProxyFactory(http.HTTPFactory): protocol=proxy.Proxy reactor.listenTCP(8001,ProxyFactory()) reactor.run()
import sgmllib.re from twisted.web import proxy,http import sys from twisted.python import log log.startLogging(sys.stdout) WEB_PORT=8000 PROXY_PORT=8001 class WordParser(sgmllib.SGMLParser): def __init__(self): sgmllib.SGMLParser.__init__(self) self.chardata=[] self.inBody=False def start_body(self,attrs): self.inBody=True def end_body(self): self.inBody=False def handle_data(self,data): if self.inBody: self.chardata.append(data) def getWords(self): #解出单词 wordFinder=re.compile(r'/w*') words=wordFinder.findall("".join(self.chardata)) words=filter(lambda word: word.strip(), words) print "WORDS ARE", words return words class WordCounter(object): ignoredWords="the a of in from to this that and or but is was be can could i you they we at".split() def __init__(self): self.words=() def addWords(self,words): for word in words: word=word.lower() if not word in self.ignoredWords: currentCount=self.words.get(word,0) self.words[word]=currentCount+1 class WordCountProxyClient(proxy.ProxyClient): def handleHeader(self,key,value): proxy.ProxyClient.handleHeader(self,key,value) if key.lower()=="content-type": if value.split(';')[0]=='text/html': self.parser=WordParser() def handleResponsePart(self,data): proxy.ProxyClient.handleResponsePart(self,data) if hasattr(self,'parser'): self.parser.feed(data) def handleResponseEnd(self): proxy.ProxyClient.handleResponseEnd(self) if hasattr(self,'parser'): self.parser.close() self.father.wordCounter.addWords(self.parser.getWords()) del(self.parser) class WordCountProxyClientFactory(proxy.ProxyClientFactory): def buildProtocol(self,addr): client=proxy.ProxyClientFactory.buildProtocol(self,addr) #升级proxy.proxyClient对象到WordCountProxyClient client.__class__=WordCountProxyClient return client class WordCountProxyRequest(proxy.ProxyRequest): protocols={'http':WordCountProxyClientFactory) def __init__(self,wordCounter,*args): self.wordCounter=wordCounter proxy.ProxyRequest.__init__(self,*args) class WordCountProxy(proxy.Proxy): def __init__(self,wordCounter): self.wordCounter=wordCounter proxy.Proxy.__init__(self) def requestFactory(self,*args) return WordCountProxyRequest(self.wordCounter,*args) class WordCountProxyFactory(http.HTTPFactory): def __init__(self,wordCount): self.wordCounter=wordCounter http.HTTPFactory.__init__(self) def buildProtocol(self,addr): protocol=WordCountProxy(self.wordCounter) return protocol #使用WEB接口展示记录的接口 class WebReportRequest(http.Request): def __init__(self,wordCounter,*args): self.wordCounter=wordCounter http.Request.__init__(self,*args) def process(self): self.setHeader("Content-Type",'text/html') words=self.wordCounter.words.items() words.sort(lambda(w1,c1),(w2,c2): cmp(c2,c1)) for word,count in words: self.write("
%s %s
"%(word,count)) self.finish() class WebReportChannel(http.HTTPChannel): def __init__(self,wordCounter): self.wordCounter=wordCounter http.HTTPChannel.__init__(self) def requestFactory(self,*args): return WebReportRequest(self.wordCounter,*args) class WebReportFactory(http.HTTPFactory): def __init__(self,wordCounter): self.wordCounter=wordCounter http.HTTPFactory.__init__(self) def buildProtocol(self,addr): return WebReportChannel(self.wordCounter) if __name__=='__main__': from twisted.internet import reactor counter=WordCounter() prox=WordCountProxyFactory(counter) reactor.listenTCP(PROXY_PORT,prox) reactor.listenTCP(WEB_PORT,WebReportFactory(counter)) reactor.run() 运行wordcountproxy.py将浏览器的代理服务器设置到8001端口。浏览其他站点,或者访问,将可以看到访问过的站点的单词频率。