twisted學習筆記 No.2 WebServer

原創博文,轉載請註明出處html

當服務器接收到一個客戶端請求後,會建立一個請求對象並傳遞到資源系統,資源系統會根據請求路徑分發到相應的資源對象,資源被要求渲染自身並返回結果到客戶端。 react

 解析HTTP Requests: git

    twisted.web.http.Request描述了一個HTTP request,咱們能夠從其中發現處理request的方法。web

   

 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 看看發生了什麼吧windows

 

處理 GET request:api

   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的內容迴應,less

訪問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()
相關文章
相關標籤/搜索