• 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()
  • 相关阅读:
    luogu4345 [SHOI2015]超能粒子炮·改(组合数/Lucas定理)
    关于 centos 7系统,iptables透明网桥实现
    C 语言实现字符串替换
    linux 程序调用system执行命令
    linux C/C++ 日志打印函数
    关于socket编程获取客户端地址笔记
    C# treeview 使用笔记
    SIP DB33标准笔记 监控图像获取
    SIP DB33标准笔记 注册/目录发送/心跳
    contos 7/redhat 7 安装mysql
  • 原文地址:https://www.cnblogs.com/tracylining/p/3346822.html
Copyright © 2020-2023  润新知