用python寫一個簡單的web框架

最近在實驗室也沒什么事情做,閑著無聊。于是想著造輪子,最后決定寫一個簡單的web框架玩玩。

STEP.1


我們首先得選擇基于什么協議來寫這種框架。我們可以選擇CGI協議,或者是WSGI接口。如果使用CGI,實際上我們只是按著CGI的規范寫了一個python程序,然后每次服務器收到請求,就fork一個程序來執行它,然后返回一個http文檔,性能比較低下。對于WSGI,而是一個存在于服務器和應用間的接口,在WSGI之前,web應用都是依賴于服務器的,現在流行的python框架都支持WSGI接口。

STEP.2 PEP-333


這一段是PEP-333 所提供的樣例代碼。

def simple_app(environ, start_response):
    """Simplest possible application object"""
    status = '200 OK'
    response_headers = [('Content-type', 'text/plain')]
    start_response(status, response_headers)
    return ['Hello world!\n']

這里的application被傳入了兩個值。

  • environ
  • start_response。
    environ是一個字典,保存了http請求的信息。
    start_response是一個函數,發送http響應。她有兩個參數status 和 start_headers。
  • status必須是由狀態編號和具體信息組成的字符串,必須符合RFC 2616。
  • start_headers是一個(header_name,header_value) 元組的列表元組列表。其中的hearder_name必須是合法的http header字段名。在RFC 2616, Section 4.2中有詳細定義。
    當然官方還給出了類的實現。
  def __init__(self, environ, start_response):

        self.environ = environ

        self.start = start_response
    def __iter__(self):

        status = '200 OK'

        response_headers = [('Content-type','text/plain')]

        self.start(status, response_headers)

        yield "Hello world!\n"

了解了如上信息后,基本上可以開始了。我們就到官方給的代碼上進行修改吧。

STEP.3 將路徑鏈接到函數


首先我們得把用戶請求的路徑,鏈接到函數。我們可以實現一個getPage方法,專門做這件事。我們所擁有的信息,只有environ['PATH_INFO']。

urls = [('^/index/$','func_index'),
        ('^/comment/$','func_comment'),
        ('^/environ/$','get_environ'),
        ('^/post/$','post_test')]#urls是提供給app開發者來做鏈接的。
    def getPage(self):
        path = self.environ['PATH_INFO']
        for pattern in self.urls:
            m = re.match(pattern[0],path)#將urls元素的第0項和path進行比對,如果匹配上了,返回函數名
            if m:
                function = getattr(self,pattern[1])#getattr方法來得到函數
                return function()
        return '404 not found'#沒匹配上任何東西

寫到這里之后,每次添加頁面,就只需要在urls列表中添加一個元祖就行了。

STEP.4 獲取模版


既然是寫web app,模版肯定是得有的。這里我提供了一種getTemplate方法來做這件事。不過我只提供了變量的替換。

    def getTemplate(self,tem_name,rep=0):
        #這個函數返回內容,tem_name是文件名字
        #參數rep是一個字典,默認為0
        f = open('template/'+tem_name)
        html = f.read()
        if(rep!=0):
            for to_replace in rep:
                strinfo = re.compile('\{\%\s*'+str(to_replace)+'\s*\%\}')
                html = strinfo.sub(rep[to_replace],html)
        return html

STEP.5 POST數據的處理


要想獲取POST數據,我們得通過environ['wsgi.input']來處理。而他實際上就是系統的標準輸入。

 environ['wsgi.input']        = sys.stdin

知道這點后就很好寫了。

    def getPost(self):
        if(self.environ['REQUEST_METHOD'] == 'POST'):
            try:
                request_body_size = int(self.environ.get('CONTENT_LENGTH', 0))#讀出content_length的值
            except:
                request_body_size = 0
            request_body = self.environ['wsgi.input'].read(request_body_size) #請求的body
            post_data = parse_qs(request_body)#parse_qs是cgi提供的方法,幫助我們處理請求
            return post_data

數據庫的鏈接


import MySQLdb
class Model(object):
    def __init__(self):
            self.host = 'localhost'
            self.port = 3306
            self.user = 'admin'
            self.passwd = 'admin'
            self.db = 'xieyi'
    def build_connect(self):
        self.conn = MySQLdb.connect(
            host = self.host,
            port = self.port,
            user = self.user,
            passwd = self.passwd,
            db = self.db
            )
    def exec_ins(self,ins):
        cur = self.conn.cursor()
        num = cur.execute(ins)
        info = {} 
        if(num>0):
            info = cur.fetchmany(num)
        cur.close()
        self.conn.commit()
        return info 
    def close(self):
        self.conn.close()

STEP.6 清理工作


很多配置如果放到代碼中,會增加閱讀負擔。于是把urls,model抽取出來。
使得配置更加方便。

STEP.7 結束


這只是一個web框架簡易的實現,僅供娛樂。如有疏漏,還望指出。
代碼po在https://github.com/bloodycoder/skeleton

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,991評論 19 139
  • 全文基于Python 2.7 macOS 10.12.2 werkzeug是Python實現的WSGI規范的使用函...
    Noskthing閱讀 7,682評論 5 21
  • 全稱為Web Server Gateway Interface,即 Web服務器網關接口。是一種標準接口規范,規定...
    超net閱讀 3,203評論 0 2
  • 又是源于一個夢。 夢到大學畢業的前夕,寢室里的四個人喝得酩酊大醉,第二天早上,誰都沒有叫醒誰,獨自收拾著行李,...
    灬You灬閱讀 764評論 1 0
  • HTML5是設計師用來打造時尚網站的最流行的編程語言之一,使用起來非常方便,并且能夠提供多種功能,例如內置的視覺元...
    鑫韭緣設計閱讀 973評論 0 8