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

之前用 Django 做過一個小的站點纠俭,感覺Django太過笨重沿量,于是就準備換一個比較輕量級的 Web 框架來玩玩。Web.py 作者已經(jīng)掛掉冤荆,項目好久沒有更新朴则,所以不準備用它。而 Flask 也是一個成熟的輕量級 Web 框架钓简,在 github 上有眾多的 Star 和 Fork乌妒,文檔和擴展也很豐富,值得學(xué)習(xí)外邓。

學(xué)習(xí)一個框架最好的方式就是用框架做一個項目撤蚊,在實戰(zhàn)中理解掌握框架。這里我用 Flask 框架坐榆,使用 Mysql 數(shù)據(jù)庫做了一個論壇系統(tǒng)拴魄。麻雀雖小,五臟俱全席镀,論壇效果圖如下:

論壇系統(tǒng)截圖
論壇系統(tǒng)截圖

下面是論壇的基本功能:

  • 完整的用戶模塊(注冊匹中、登錄,更改豪诲、找回密碼顶捷、信息修改、站內(nèi)消息通知)屎篱;
  • 豐富的論壇模塊(創(chuàng)建服赎、回復(fù)話題,站內(nèi)搜索交播,markdown支持重虑,@user 提醒);
  • 強大的后臺管理秦士,支持屏蔽用戶缺厉、話題、評論,支持各種條件搜索話題提针、評論命爬;

本博客將會用一系列文章,記錄論壇系統(tǒng)搭建的過程辐脖,希望對剛?cè)腴TWeb開發(fā)的同學(xué)有所幫助饲宛。

我們經(jīng)常聽說 Django, Flask 這些 python 語言的Web 框架,那么框架到底是什么嗜价,Web框架和Web服務(wù)器(Nginx, Apache等)有什么區(qū)別艇抠?離開框架還能用 Python 搭建Web站點嗎?要解決這些疑問炭剪,我們有必要來理解下 Web 服務(wù)器的工作原理练链,以及 Web 框架的本質(zhì)。

Web 服務(wù)器

當我們在瀏覽器輸入URL后奴拦,瀏覽器會先請求DNS服務(wù)器媒鼓,獲得請求站點的 IP 地址。然后發(fā)送一個HTTP Request(請求)給擁有該 IP 的主機错妖,接著就會接收到服務(wù)器給我們的 HTTP Response(響應(yīng))绿鸣,瀏覽器經(jīng)過渲染后,以一種較好的效果呈現(xiàn)給我們暂氯。這個過程中潮模,正是Web服務(wù)器在幕后默默做貢獻。

簡單來說痴施,Web服務(wù)器是在運行在物理服務(wù)器上的一個程序擎厢,它永久地等待客戶端(主要是瀏覽器,比如Chrome辣吃,F(xiàn)irefox等)發(fā)送請求动遭。當收到請求之后,它會生成相應(yīng)的響應(yīng)并將其返回至客戶端神得。Web服務(wù)器通過HTTP協(xié)議與客戶端通信厘惦,因此也被稱為HTTP服務(wù)器。

Web 服務(wù)器

Web服務(wù)器的工作原理并不復(fù)雜哩簿,一般可分成如下4個步驟:建立連接宵蕉、請求過程、應(yīng)答過程以及關(guān)閉連接节榜。

  1. 建立連接:客戶機通過TCP/IP協(xié)議建立到服務(wù)器的TCP連接羡玛。
  2. 請求過程:客戶端向服務(wù)器發(fā)送HTTP協(xié)議請求包,請求服務(wù)器里的資源文檔宗苍。
  3. 應(yīng)答過程:服務(wù)器向客戶機發(fā)送HTTP協(xié)議應(yīng)答包稼稿,如果請求的資源包含有動態(tài)語言的內(nèi)容亿遂,那么服務(wù)器會調(diào)用動態(tài)語言的解釋引擎負責處理“動態(tài)內(nèi)容”,并將處理得到的數(shù)據(jù)返回給客戶端渺杉。由客戶端解釋HTML文檔,在客戶端屏幕上渲染圖形結(jié)果挪钓。
  4. 關(guān)閉連接:客戶機與服務(wù)器斷開是越。

下面我們實現(xiàn)一個簡單的 Web 服務(wù)器。運行示例程序后碌上,會監(jiān)聽本地端口 8000倚评,在瀏覽器訪問 http://localhost:8000 就能看到響應(yīng)內(nèi)容。而我們的程序也能夠打印出客戶端發(fā)來的請求內(nèi)容馏予,如下圖:

簡單Web服務(wù)器
簡單Web服務(wù)器

這里Request 和 Response 都需要遵守 HTTP 協(xié)議天梧,關(guān)于 HTTP 協(xié)議的詳細內(nèi)容,可以讀讀《HTTP 權(quán)威指南》霞丧,或者看我整理的HTTP 部分內(nèi)容呢岗。

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

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

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

Web 應(yīng)用程序

Web 服務(wù)器接受 Http Request葱弟,返回 Response,很多時候 Response 并不是靜態(tài)文件饵骨,因此需要有一個應(yīng)用程序根據(jù) Request 生成相應(yīng)的 Response翘悉。這里的應(yīng)用程序主要用來處理相關(guān)業(yè)務(wù)邏輯,讀取或者更新數(shù)據(jù)庫居触,根據(jù)不同 Request 返回相應(yīng)的 Response妖混。注意這里并不是 Web 服務(wù)器本身來做這件事,它只負責 Http 協(xié)議層面和一些諸如并發(fā)處理轮洋,安全制市,日志等相關(guān)的事情。

應(yīng)用程序可以用各種語言編寫(Java, PHP, Python, Ruby等)弊予,這個應(yīng)用程序會從Web服務(wù)器接收客戶端的請求祥楣,處理完成后,再返回響應(yīng)給Web服務(wù)器,最后由Web服務(wù)器返回給客戶端误褪。整個架構(gòu)如下:

Web應(yīng)用程序
Web應(yīng)用程序

以 Python 為例责鳍,使用Python開發(fā)Web,最原始和直接的辦法是使用CGI標準兽间,在1998年這種方式很流行历葛。首先確保 Web 服務(wù)器支持CGI及已經(jīng)配置了CGI的處理程序,然后設(shè)置好CGI目錄嘀略,在目錄里面添加相應(yīng)的 python 文件恤溶,每一個 python 文件處理相應(yīng)輸入,生成一個 html 文件即可帜羊,如下例:

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

print "Content-type:text/html"
print         # 空行咒程,告訴服務(wù)器結(jié)束頭部
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 網(wǎng)頁內(nèi)容。直接通過 CGI 寫 Web 應(yīng)用程序看起來很簡單讼育,每一個文件處理輸入帐姻,生成html。但是實際開發(fā)中窥淆,可能會遇到許多不方便的地方卖宠。比如:

  • 每個獨立的CGI腳本可能會重復(fù)寫數(shù)據(jù)庫連接,關(guān)閉的代碼忧饭;
  • 后端開發(fā)者會看到一堆 Content-Type 等和自己無關(guān)的 html 頁面元素扛伍;

Web 框架

早期開發(fā)站點確做了許多重復(fù)性勞動,后來為了減少重復(fù)词裤,避免寫出龐雜刺洒,混亂的代碼,人們將 Web 開發(fā)的關(guān)鍵性過程提取出來吼砂,開發(fā)出了各種 Web 框架逆航。有了框架,就可以專注于編寫清晰渔肩、易維護的代碼因俐,無需關(guān)心數(shù)據(jù)庫連接之類的重復(fù)性工作。

其中一種比較經(jīng)典的Web框架采用了 MVC 架構(gòu)周偎,如下圖所示:

MVC 架構(gòu)
MVC 架構(gòu)

用戶輸入 URL阁苞,客戶端發(fā)送請求钱反,控制器(Controller)首先會拿到請求,然后用模型(Models)從數(shù)據(jù)庫取出所有需要的數(shù)據(jù),進行必要的處理义郑,將處理后的結(jié)果發(fā)送給 視圖(View)按傅,視圖利用獲取到的數(shù)據(jù)照棋,進行渲染生成 Html Response返回給客戶端。

以 python web 框架 flask 為例衷敌,框架本身并不限定我們用哪種架構(gòu)來組織我們的應(yīng)用,不過 flask 可以很好地支持以 MVC 方式組織應(yīng)用拓瞪。

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

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

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

@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 服務(wù)器網(wǎng)關(guān)接口

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

那么,怎樣確逼ㄒ可以在不修改Web服務(wù)器代碼或網(wǎng)絡(luò)框架代碼的前提下粥血,使用自己選擇的服務(wù)器,并且匹配多個不同的網(wǎng)絡(luò)框架呢酿箭?答案是接口复亏,設(shè)計一套雙方都遵守的接口就可以了。對python來說缭嫡,就是WSGI(Web Server Gateway Interface缔御,Web服務(wù)器網(wǎng)關(guān)接口)。其他編程語言也擁有類似的接口:例如Java的Servlet API和Ruby的Rack妇蛀。

Python WSGI的出現(xiàn)耕突,讓開發(fā)者可以將 Web 框架與 Web 服務(wù)器的選擇分隔開來,不再相互限制∑兰埽現(xiàn)在眷茁,你可以真正地將不同的 Web 服務(wù)器與Web框架進行混合搭配,選擇滿足自己需求的組合纵诞。例如上祈,可以使用 Gunicorn 或Nginx/uWSGI來運行Django、Flask或web.py應(yīng)用浙芙。

WSGI 適配
WSGI 適配

下一篇我們將會仔細分析 WSGI 接口標準登刺,然后一起來寫一個簡單的 WSGI Web 服務(wù)器。

更多閱讀

自己動手開發(fā)網(wǎng)絡(luò)服務(wù)器(一)
自己動手開發(fā)網(wǎng)絡(luò)服務(wù)器(二)
自己動手開發(fā)網(wǎng)絡(luò)服務(wù)器(三)
Web服務(wù)器網(wǎng)關(guān)接口實現(xiàn)原理分析
Python最佳實踐指南:Web 應(yīng)用
淺談Python web框架
Python CGI編程
Django vs Flask vs Pyramid: Choosing a Python Web Framework
PEP 333 -- Python Web Server Gateway Interface v1.0
WSGI簡介
Model-View-Controller (MVC) Explained -- With Legos

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末茁裙,一起剝皮案震驚了整個濱河市塘砸,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌晤锥,老刑警劉巖掉蔬,帶你破解...
    沈念sama閱讀 206,839評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件廊宪,死亡現(xiàn)場離奇詭異,居然都是意外死亡女轿,警方通過查閱死者的電腦和手機箭启,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蛉迹,“玉大人傅寡,你說我怎么就攤上這事”本龋” “怎么了荐操?”我有些...
    開封第一講書人閱讀 153,116評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長珍策。 經(jīng)常有香客問我托启,道長,這世上最難降的妖魔是什么攘宙? 我笑而不...
    開封第一講書人閱讀 55,371評論 1 279
  • 正文 為了忘掉前任屯耸,我火速辦了婚禮,結(jié)果婚禮上蹭劈,老公的妹妹穿的比我還像新娘疗绣。我一直安慰自己,他們只是感情好铺韧,可當我...
    茶點故事閱讀 64,384評論 5 374
  • 文/花漫 我一把揭開白布多矮。 她就那樣靜靜地躺著,像睡著了一般哈打。 火紅的嫁衣襯著肌膚如雪工窍。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,111評論 1 285
  • 那天前酿,我揣著相機與錄音患雏,去河邊找鬼。 笑死罢维,一個胖子當著我的面吹牛淹仑,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播肺孵,決...
    沈念sama閱讀 38,416評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼匀借,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了平窘?” 一聲冷哼從身側(cè)響起吓肋,我...
    開封第一講書人閱讀 37,053評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎瑰艘,沒想到半個月后是鬼,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體肤舞,經(jīng)...
    沈念sama閱讀 43,558評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,007評論 2 325
  • 正文 我和宋清朗相戀三年均蜜,在試婚紗的時候發(fā)現(xiàn)自己被綠了李剖。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,117評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡囤耳,死狀恐怖篙顺,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情充择,我是刑警寧澤德玫,帶...
    沈念sama閱讀 33,756評論 4 324
  • 正文 年R本政府宣布,位于F島的核電站椎麦,受9級特大地震影響化焕,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜铃剔,卻給世界環(huán)境...
    茶點故事閱讀 39,324評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望查刻。 院中可真熱鬧键兜,春花似錦、人聲如沸穗泵。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽佃延。三九已至现诀,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間履肃,已是汗流浹背仔沿。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留尺棋,地道東北人封锉。 一個月前我還...
    沈念sama閱讀 45,578評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像膘螟,于是被迫代替她去往敵國和親成福。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,877評論 2 345

推薦閱讀更多精彩內(nèi)容