從零開始搭建論壇(一):Web服務器與Web框架

作者:selfboot

之前用 Django 做過一個小的站點,感覺Django太過笨重,于是就準備換一個比較輕量級的 Web 框架來玩玩。Web.py 作者已經掛掉,項目好久沒有更新,所以不準備用它。而 Flask 也是一個成熟的輕量級 Web 框架,在 github 上有眾多的 Star 和 Fork,文檔和擴展也很豐富,值得學習。

學習一個框架最好的方式就是用框架做一個項目,在實戰中理解掌握框架。這里我用 Flask 框架,使用 Mysql 數據庫做了一個論壇系統。麻雀雖小,五臟俱全,論壇效果圖如下:

下面是論壇的基本功能:

  • 完整的用戶模塊(注冊、登錄,更改、找回密碼、信息修改、站內消息通知);
  • 豐富的論壇模塊(創建、回復話題,站內搜索,markdown支持,@user 提醒);
  • 強大的后臺管理,支持屏蔽用戶、話題、評論,支持各種條件搜索話題、評論;

本博客將會用一系列文章,記錄論壇系統搭建的過程,希望對剛入門Web開發的同學有所幫助。

我們經常聽說 Django, Flask 這些 python 語言的Web 框架,那么框架到底是什么,Web框架和Web服務器(Nginx, Apache等)有什么區別?離開框架還能用 Python 搭建Web站點嗎?要解決這些疑問,我們有必要來理解下 Web 服務器的工作原理,以及Web 框架的本質。

Web 服務器


當我們在瀏覽器輸入URL后,瀏覽器會先請求DNS服務器,獲得請求站點的 IP 地址。然后發送一個HTTP Request(請求)給擁有該 IP 的主機,接著就會接收到服務器給我們的 HTTP Response(響應),瀏覽器經過渲染后,以一種較好的效果呈現給我們。這個過程中,正是Web服務器在幕后默默做貢獻。

簡單來說,Web服務器是在運行在物理服務器上的一個程序,它永久地等待客戶端(主要是瀏覽器,比如Chrome,Firefox等)發送請求。當收到請求之后,它會生成相應的響應并將其返回至客戶端。Web服務器通過HTTP協議與客戶端通信,因此也被稱為HTTP服務器。


Web服務器的工作原理并不復雜,一般可分成如下4個步驟:建立連接、請求過程、應答過程以及關閉連接

  1. 建立連接:客戶機通過TCP/IP協議建立到服務器的TCP連接。
  2. 請求過程:客戶端向服務器發送HTTP協議請求包,請求服務器里的資源文檔。
  3. 應答過程:服務器向客戶機發送HTTP協議應答包,如果請求的資源包含有動態語言的內容,那么服務器會調用動態語言的解釋引擎負責處理“動態內容”,并將處理得到的數據返回給客戶端。由客戶端解釋HTML文檔,在客戶端屏幕上渲染圖形結果。
  4. 關閉連接:客戶機與服務器斷開。

下面我們實現一個簡單的 Web 服務器。運行示例程序點擊預覽后,會監聽本地端口 8000,在瀏覽器訪問 http://localhost:8000 就能看到響應內容。而我們的程序也能夠打印出客戶端發來的請求內容,如下圖:


這里Request 和 Response 都需要遵守 HTTP 協議,關于 HTTP 協議的詳細內容,可以讀讀《HTTP 權威指南》,或者看我整理的HTTP 部分內容

雖然說web服務器的主要工作是根據request返回response,但是實際中的 Web 服務器遠遠比上面示例的復雜的多,因為要考慮的因素實在是太多了,比如:

  • 緩存機制:講一些經常被訪問的頁面緩存起來,提高響應速度;
  • 安全:防止黑客的各種攻擊,比如 SYN Flood 攻擊;
  • 并發處理:如何響應不同客戶端同時發起的請求;
  • 日志:記錄訪問日至,方便做一些分析。

目前在UNIX和LINUX平臺下使用最廣泛的免費 Web 服務器有Apache和 Nginx 。

Web 應用程序


Web 服務器接受 Http Request,返回 Response,很多時候 Response 并不是靜態文件,因此需要有一個應用程序根據 Request 生成相應的 Response。這里的應用程序主要用來處理相關業務邏輯,讀取或者更新數據庫,根據不同 Request 返回相應的 Response。注意這里并不是 Web 服務器本身來做這件事,它只負責 Http 協議層面和一些諸如并發處理,安全,日志等相關的事情。

應用程序可以用各種語言編寫(Java, PHP, Python, Ruby等),這個應用程序會從Web服務器接收客戶端的請求,處理完成后,再返回響應給Web服務器,最后由Web服務器返回給客戶端。整個架構如下:

以 Python 為例,使用Python開發Web,最原始和直接的辦法是使用CGI標準,在1998年這種方式很流行。首先確保 Web 服務器支持CGI及已經配置了CGI的處理程序,然后設置好CGI目錄,在目錄里面添加相應的 python 文件,每一個 python 文件處理相應輸入,生成一個 html 文件即可,如下例:

#!/usr/bin/python
# -*- coding: UTF-8 -*-

print "Content-type:text/html"
print         # 空行,告訴服務器結束頭部
print '<html>'
print '<head>'
print '<meta charset="utf-8">'
print '</head>'
print '<body>'
print '<h2>Hello Word! 我是一個CGI程序</h2>'
print '</body>'
print '</html>’

這樣在瀏覽器訪問該文件就可以得到一個簡單的 Hello World 網頁內容。直接通過 CGI 寫 Web 應用程序看起來很簡單,每一個文件處理輸入,生成html。但是實際開發中,可能會遇到許多不方便的地方。比如:

  • 每個獨立的CGI腳本可能會重復寫數據庫連接,關閉的代碼;
  • 后端開發者會看到一堆 Content-Type 等和自己無關的 html 頁面元素;

Web 框架


早期開發站點確做了許多重復性勞動,后來為了減少重復,避免寫出龐雜,混亂的代碼,人們將 Web 開發的關鍵性過程提取出來,開發出了各種 Web 框架。有了框架,就可以專注于編寫清晰、易維護的代碼,無需關心數據庫連接之類的重復性工作。

其中一種比較經典的Web框架采用了 MVC 架構,如下圖所示:

用戶輸入 URL,客戶端發送請求,控制器(Controller)首先會拿到請求,然后用模型(Models)從數據庫取出所有需要的數據,進行必要的處理,將處理后的結果發送給 視圖(View),視圖利用獲取到的數據,進行渲染生成 Html Response返回給客戶端。

以 python web 框架 flask 為例,框架本身并不限定我們用哪種架構來組織我們的應用,不過 flask 可以很好地支持以 MVC 方式組織應用。

控制器:flask 可以用裝飾器來添加路由項,如下:

@app.route('/')
def main_page():
    pass

模型:主要用來取出需要的數據,如下面函數中操作:

@app.route('/')
def main_page():
    """Searches the database for entries, then displays them."""
    db = get_db()
    cur = db.execute('select * from entries order by id desc')
    entries = cur.fetchall()
    return render_template('index.html', entries=entries)

視圖:flask 利用 jinja2 來渲染頁面,下面的模版文件指定了頁面的樣式:

{% for entry in entries %}
<li>
  <h2>{{ entry.title }}</h2>
  <div>{{ entry.text|safe }}</div>
</li>
{% else %}
<li><em>No entries yet. Add some!</em></li>
{% endfor %}

Web 服務器網關接口


我們知道Python有著許多的 Web 框架,而同時又有著許多的 Web 服務器(Apache, Nginx, Gunicorn等),框架和Web服務器之間需要進行通信,如果在設計時它們之間不可以相互匹配的,那么選擇了一個框架就會限制對 Web 服務器的選擇,這顯然是不合理的。

那么,怎樣確保可以在不修改Web服務器代碼或網絡框架代碼的前提下,使用自己選擇的服務器,并且匹配多個不同的網絡框架呢?答案是接口,設計一套雙方都遵守的接口就可以了。對python來說,就是WSGI(Web Server Gateway Interface,Web服務器網關接口)。其他編程語言也擁有類似的接口:例如Java的Servlet API和Ruby的Rack。

Python WSGI的出現,讓開發者可以將 Web 框架與 Web 服務器的選擇分隔開來,不再相互限制。現在,你可以真正地將不同的 Web 服務器與Web框架進行混合搭配,選擇滿足自己需求的組合。例如,可以使用 Gunicorn 或Nginx/uWSGI來運行Django、Flask或web.py應用。


PyChina將聯合JetBrain(出品PyCharm的公司)一起在北京舉辦一次Python沙龍活動。

時間:11月26日晚上19:00-21:00

地點:科技寺北新橋 北京市東城區東四北大街107號科林大廈B座107室(近北新橋地鐵站)

歡迎大家報名參加本次活動,特別需要志愿者來幫忙組織本次活動。

詳情請點擊此處

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,345評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,494評論 3 416
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,283評論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,953評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,714評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,186評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,255評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,410評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,940評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,776評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,976評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,518評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,210評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,642評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,878評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,654評論 3 391
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,958評論 2 373

推薦閱讀更多精彩內容