原创博文,转载请注明出处。
当服务器接收到一个客户端请求后,会创建一个请求对象并传递到资源系统,资源系统会根据请求路径分发到相应的资源对象,资源被要求渲染自身并返回结果到客户端。
解析HTTP Requests:
twisted.web.http.Request描述了一个HTTP request,我们可以从其中发现处理request的方法。
1 from twisted.internet import reactor 2 from twisted.web import http 3 4 class MyRequestHandler(http.Request): 5 resources={ 6 '/':'<h1>Home</h1>Home page', 7 '/about':'<h1>About</h1>All about me', 8 } 9 def process(self): 10 self.setHeader('Content-Type','text/html') 11 if self.resources.has_key(self.path): 12 self.write(self.resources[self.path]) 13 else: 14 self.setResponseCode(http.NOT_FOUND) 15 self.write("<h1>Not Found</h1>Sorry, no such source") 16 self.finish() 17 18 class MyHTTP(http.HTTPChannel): #继承高级API http.HTTPChannel 19 requestFactory=MyRequestHandler 20 21 class MyHTTPFactory(http.HTTPFactory): 22 def buildProtocol(self,addr): 23 return MyHTTP() 24 25 reactor.listenTCP(8000,MyHTTPFactory()) 26 reactor.run()
执行程序后,在浏览器输入http://localhost:8000/和http://localhost:8000/about 看看发生了什么吧
处理 GET request:
from twisted.web.server import Site
from twisted.web.static import File
利用Site,我们不在担心HTTP协议的细节问题,这是http.HTTPFactory的子类,可以管理HTTP会话并且把resources 分发给我们。
from twisted.internet import reactor from twisted.web.server import Site from twisted.web.static import File root = File('/var/www/mysite') root.putChild("doc",File("/usr/share/doc")) root.putChild("logs",File("/var/log/mysitelogs")) factory=Site(root) reactor.listenTCP(8000,factory) reactor.run()
现在访问 http://localhost:8000/将会得到来自本地文件系统/var/www/mysite的内容回应,访问 localhost:8000/doc将会得到/usr/share/doc的内容回应,
访问localhost:8000/logs将会得到来自/var/log/mysitelogs的内容回应。本人测试在windows环境下尚且无法支持,留着以后再来研究。
提供动态内容:
与提供静态内容不同的是,你需要定义一个继承自Resource的子类去决定一个Site所能提供的内容。
from twisted.internet import reactor from twisted.web.resource import Resource from twisted.web.server import Site import time class ClockPage(Resource): isLeaf=True def render_GET(self,request): return "The local time is %s"%(time.ctime(),) resource=ClockPage() factory=Site(resource) reactor.listenTCP(8000,factory) reactor.run()
关于Resource的API文档:点击进入
我们需要定义render_GET render_POST render_HEAD等等“render_METHOD”(其中METHOD是HTTP做出请求的方法)
render_METHOD methods are expected to return a string which will be the rendered page, unless the return value is twisted.web.server.NOT_DONE_YET, in which case it is this class's responsibility to write the results to request.write(data), then call request.finish().
isleaf变量用来描述一个source是否拥有子类,如果设置为False,访问所有的URL将会产生404NO such resource
from twisted.internet import reactor from twisted.web.resource import Resource,NoResource from twisted.web.server import Site from calendar import calendar class YearPage(Resource): def __init__(self,year): Resource.__init__(self) self.year=year def render_GET(self,request): return "<html><body><pre>%s</pre></body></html>"%(calendar(self.year),) class CalendarHome(Resource): def getChild(self,name,request): if name=='': return self if name.isdigit(): return YearPage(int(name)) else: return NoResource() def render_GET(self,request): return "<html><body>Welcome to the calendar server!</body></html>" root=CalendarHome() factory=Site(root) reactor.listenTCP(8000,factory) reactor.run()
本例示范了一个日历服务器,如输入http://localhost:8000/2012就可以显示2012全年的日历,
Redirects重定向:
from twisted.web.util import redirectTo
我们修改上例中CalendarHome
from twisted.web.util import redirectTo from datetime import datetime def render_GET(self,request): return redirectTo(datetime.now().year,request)
当我们访问http://localhost:8000/时,datetime.now().year就会作为参数链接在URL的后面即http://localhost:8000/2013
处理POST Requests:
from twisted.internet import reactor from twisted.web.resource import Resource from twisted.web.server import Site import cgi class FormPage(Resource): isLeaf=True def render_GET(self,request): return """ <html> <body> <form method="POST"> <input name="form-field" type="text"/> <input type="submit"/> </form> </body> </html> """ def render_POST(self,request): return """ <html> <body>You submitted: %s</body> </html> """%(cgi.escape(request.args["form-field"][0],)) #cgi.escape(s,[quote,])把在s中的“&”、“<”和“>”转化成HTML安全序列 使用request.args字典存取提交的HTML表单数据 factory=Site(FormPage()) reactor.listenTCP(8000,factory) reactor.run()
异步处理:
如果发生了请求阻塞,这时候我们就应该使用异步处理方法。
先看一个例子:
from twisted.internet import reactor from twisted.web.resource import Resource from twisted.web.server import Site import time class BusyPage(Resource): isLeaf=True def render_GET(self,request): time.sleep(5) return "Finally done, at %s"%(time.asctime(),) factory=Site(BusyPage()) reactor.listenTCP(8000,factory) reactor.run()
对于每一次请求我们等待5秒钟,加入我们在浏览器中打开多个标签并输入http://localhost:8000/,我们会发现服务器的回应是连续的,也就是说这几个回应所显示的时间依次相差5秒钟,第一个打开的页面和最后一个打开的页面相差N*5秒,这对于我们将是灾难性的。所以我们有必要进行异步处理。
我们看一下改进的程序:我们使用了deferred,在本例程中你可能会发现requests也是连续的,这是由于你所用的浏览器对于同一resource的请求连续。
# -*- coding: cp936 -*- from twisted.internet import reactor from twisted.internet.task import deferLater from twisted.web.resource import Resource from twisted.web.server import Site, NOT_DONE_YET import time class BusyPage(Resource): isLeaf=True def _delayedRender(self,request): request.write("Fianlly done, at %s"%(time.asctime(),))#渲染网页 request.finish() def render_GET(self,request): d=deferLater(reactor,5,lambda:request)#返回一个由request引起的deferred d.addCallback(self._delayedRender) return NOT_DONE_YET#它告知Resource有些事情是异步的而且尚未完成,直到你调用了request.finish() factory =Site(BusyPage()) reactor.listenTCP(8000,factory) reactor.run()