原創博文,轉載請註明出處。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()