webpy源碼閱讀--開篇

   我剛開始學習webpy的時候根據官網文檔能完成大部分功能,但用着用着仍是感受有些不太爽感受本身使用不靈活,有些功能想實現不知道該怎樣入手,而如今網上關於深刻使用webpy的開發資料也不多。因此決定仍是本身來看看源碼吧,很慶幸webpy源碼很少(應該是不多)看兩個小時就能理清楚了。 python

1  首先看看webpy的源碼目錄結構 android

這麼少的代碼寫出一個web服務器很顯然它確定是依靠了其餘的某些工具 web

 2 找到源碼分析的切入點, 如下是webpy官網提供的helloworld程序代碼 服務器

import web

urls = ("/.*", "hello")
app = web.application(urls, globals())

class hello:
    def GET(self):
        return 'Hello, world!'

if __name__ == "__main__":
    app.run()

很明顯 application.run()就是程序的啓動入口了。打開application.py看代碼果真不少,不過飄過其餘的代碼先不看找到run()函數其代碼爲: app

def run(self, *middleware):
          return wsgi.runwsgi(self.wsgifunc(*middleware))

好吧它又調轉到了wsgi.py的runwsgi()函數了其代碼爲(該代碼能夠基本飄過只看最後一行) 框架

def runwsgi(func):
    """
    Runs a WSGI-compatible `func` using FCGI, SCGI, or a simple web server,
    as appropriate based on context and `sys.argv`.
    """
    
    if os.environ.has_key('SERVER_SOFTWARE'): # cgi
        os.environ['FCGI_FORCE_CGI'] = 'Y'

    if (os.environ.has_key('PHP_FCGI_CHILDREN') #lighttpd fastcgi
      or os.environ.has_key('SERVER_SOFTWARE')):
        return runfcgi(func, None)
    
    if 'fcgi' in sys.argv or 'fastcgi' in sys.argv:
        args = sys.argv[1:]
        if 'fastcgi' in args: args.remove('fastcgi')
        elif 'fcgi' in args: args.remove('fcgi')
        if args:
            return runfcgi(func, validaddr(args[0]))
        else:
            return runfcgi(func, None)
    
    if 'scgi' in sys.argv:
        args = sys.argv[1:]
        args.remove('scgi')
        if args:
            return runscgi(func, validaddr(args[0]))
        else:
            return runscgi(func)
    
    
    server_addr = validip(listget(sys.argv, 1, ''))
    if os.environ.has_key('PORT'): # e.g. Heroku
        server_addr = ('0.0.0.0', intget(os.environ['PORT']))
    
    return httpserver.runsimple(func, server_addr)

上面這段代碼主要的意思就是經過傳人的命令行參數進行不一樣的初始化,最後傳人到httpservice.runsimple()函數了 而且將啓動的application(func)也傳了進去一下爲httpservice.runsimple()源碼: 函數

def runsimple(func, server_address=("0.0.0.0", 8080)):
    global server
    func = StaticMiddleware(func)
    func = LogMiddleware(func)
    
    server = WSGIServer(server_address, func)

    if server.ssl_adapter:
        print "https://%s:%d/" % server_address
    else:
        print "http://%s:%d/" % server_address

    try:
        server.start()
    except (KeyboardInterrupt, SystemExit):
        server.stop()
        server = None

 看到這段代碼我就豁然開朗了原理8080端口默認是在這裏啊! 工具

再看下面的代碼 源碼分析

    func = StaticMiddleware(func)
    func = LogMiddleware(func) 學習

它們分別是加入了兩個路由第一個是咱們靜態資源文件夾路由"/static/",另一個是日誌路由(所謂路由能夠理解爲一個攔截器,路由攔截自定url路徑的數據)不明白的話仍是看代碼比較清楚 以StaticMiddleware爲例他們都在httpservice.py文件中

class StaticMiddleware:
    """WSGI middleware for serving static files."""
    def __init__(self, app, prefix='/static/'):
        #保存下一個路由
        self.app = app
        #保存本身將要攔截的路徑
        self.prefix = prefix
        
    def __call__(self, environ, start_response):
        #當用戶請求是wsgi將依次調用路由器的這個函數
        path = environ.get('PATH_INFO', '')
        path = self.normpath(path)
        #判斷一下若是是我要攔截的路徑"/static/"
        if path.startswith(self.prefix):
            return StaticApp(environ, start_response)
        else:
            #若是不是就交由下一個路由處理
            return self.app(environ, start_response)

   這個地方其實挺關鍵由於webpy的application自己也能夠理解爲一個路由(這樣你也就能夠路徑application中其實還能夠添加下一層application了)webpy使用子應用http://webpy.org/cookbook/subapp.zh-cn

   讀到這裏你可能會有點不明白了  def __call__(self, environ, start_response):這傳入的兩個參數  environ, start_response是怎麼來的?有什麼意義?

   其實這是python的wsgi協議裏面定義的東東了你能夠經過這篇文章瞭解wsgi的部分知識http://linluxiang.iteye.com/blog/799163

  若是你看明白了wsgi的知識也就天然明白了runsimple()函數中server.start()是個什麼了,它其實就是啓動wsgiserver服務

 經過以上的學習你就能夠寫本身的路由了(仿照StaticMiddleware哦),其實webpy在application.run()就定義了路由接口,開發者能夠寫本身的路由而後傳人run()函數 啓動的時候會一步一步的傳遞到wgsi中。以下代碼

'''
Created on 2013-10-15

@author: liangqianwu
'''
#_*_ coding:utf-8_*_ 
import web
urls = ("/.*", "hello")
app = web.application(urls, globals())

class hello:
    def GET(self):
        return 'Hello, world!'
def my(environ, start_response):
    status = '200 OK'
    output = 'this is my Middleware!'
    response_headers = [('Content-type', 'text/plain')]
    write = start_response(status, response_headers)
    write('Hello ')
    return [output]
class myMiddleware:
    """WSGI middleware for serving static files."""
    def __init__(self, app, prefix='/my'):
        self.app = app
        self.prefix = prefix
        
    def __call__(self, environ, start_response):
        path = environ.get('PATH_INFO', '')

        if path.startswith(self.prefix):
            return my(environ, start_response)
        else:
            return self.app(environ, start_response)
if __name__ == "__main__":
    app.run(myMiddleware)

有圖有真相

 

 本人最近作了一個android插件化開發框架能夠不安裝運行apk文件的插件,歡迎開發者們去試試網址www.apkplug.com

相關文章
相關標籤/搜索