twisted学习笔记 No.2 WebServer

原创博文,转载请注明出处

当服务器接收到一个客户端请求后,会创建一个请求对象并传递到资源系统,资源系统会根据请求路径分发到相应的资源对象,资源被要求渲染自身并返回结果到客户端。 

 解析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()
posted @ 2013-09-30 10:17  枫桦宁  阅读(2504)  评论(1编辑  收藏  举报