對框架與HTTP協議的認識
目錄
一、框架
1、什麼是框架
框架(Framework)是整個或部分系統的可重用設計,表現為一組抽象構件及構件例項間互動的方法;另一種定義認為,框架是可被應用開發者定製的應用骨架。前者是從應用方面而後者是從目的方面給出的定義。
簡單理解就是: 框架,即framework。其實就是某種應用的半成品,就是一組元件,供你選用完成你自己的系統。簡單說就是使用別人搭好的舞臺,你來做表演。而且,框架一般是成熟的,不斷升級的軟體
2、為什麼要用框架
因為軟體系統發展到今天已經很複雜了,特別是伺服器端軟體,設計到的知識,內容,問題太多。在某些方面使用別人成熟的框架,就相當於讓別人幫你完成一些基礎工作,你只需要集中精力完成系統的業務邏輯設計。而且框架一般是成熟,穩健的,他可以處理系統很多細節問題,比如,事物處理,安全性,資料流控制等問題。還有框架一般都經過很多人使用,所以結構很好,所以擴充套件性也很好,而且它是不斷升級的,你可以直接享受別人升級程式碼帶來的好處。
框架一般處在低層應用平臺(如J2EE)和高層業務邏輯之間的中間層。
3、為什麼要進行框架開發
框架的最大好處就是重用。面向物件系統獲得的最大的複用方式就是框架,一個大的應用系統往往可能由多層互相協作的框架組成。
由於框架能重用程式碼,因此從一已有構件庫中建立應用變得非常容易,因為構件都採用框架統一定義的介面,從而使構件間的通訊簡單。
框架能重用設計。它提供可重用的抽象演算法及高層設計,並能將大系統分解成更小的構件,而且能描述構件間的內部介面。這些標準介面使在已有的構件基礎上通過組裝建立各種各樣的系統成為可能。只要符合介面定義,新的構件就能插入框架中,構件設計者就能重用構架的設計。
框架還能重用分析。所有的人員若按照框架的思想來分析事務,那麼就能將它劃分為同樣的構件,採用相似的解決方法,從而使採用同一框架的分析人員之間能進行溝通。
4、採用框架進行軟體開發的特點
- - 建立更加開放的系統;
- - 重用程式碼大大增加,軟體生產效率和質量也得到了提高
- - 軟體設計人員要專注於對領域的瞭解,使需求分析更充分;
- - 儲存了經驗,可以讓那些經驗豐富的人員去設計框架和領域構件,而不必限於低層程式設計;
- - 允許採用快速原型技術;
- - 粒度的重用使得平均開發費用降低,開發速度加快,開發人員減少,維護費用降低,而引數化框架使得適應性、靈活性增強。
5、框架本質
對於所有的Web應用,本質上其實就是一個socket服務端,使用者的瀏覽器其實就是一個socket客戶端。
# !/usr/bin/env python
# -*- coding:utf-8 -*-
import socket
def handle_request(client):
buf = client.recv(1024)
client.send("HTTP/1.1 200 OK\r\n\r\n")
client.send("Hello, Seven")
def main():
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(('localhost',8080))
sock.listen(5)
while True:
connection, address = sock.accept()
handle_request(connection)
connection.close()
if __name__ == '__main__':
main()
上述通過socket來實現了其本質,而對於真實開發中的python web程式來說,一般會分為兩部分:伺服器程式和應用程式。伺服器程式負責對socket伺服器進行封裝,並在請求到來時,對請求的各種資料進行整理。應用程式則負責具體的邏輯處理。為了方便應用程式的開發,就出現了眾多的Web框架,例如:Django、Flask、web.py 等。不同的框架有不同的開發方式,但是無論如何,開發出的應用程式都要和伺服器程式配合,才能為使用者提供服務。這樣,伺服器程式就需要為不同的框架提供不同的支援。這樣混亂的局面無論對於伺服器還是框架,都是不好的。對伺服器來說,需要支援各種不同框架,對框架來說,只有支援它的伺服器才能被開發出的應用使用。這時候,標準化就變得尤為重要。我們可以設立一個標準,只要伺服器程式支援這個標準,框架也支援這個標準,那麼他們就可以配合使用。一旦標準確定,雙方各自實現。這樣,伺服器可以支援更多支援標準的框架,框架也可以使用更多支援標準的伺服器。
二、HTTP協議
1、HTTP概述
HTTP(hypertext transport protocol),即超文字傳輸協議。這個協議詳細規定了瀏覽器和全球資訊網伺服器之間互相通訊的規則。
HTTP就是一個通訊規則,通訊規則規定了客戶端傳送給伺服器的內容格式,也規定了伺服器傳送給客戶端的內容格式。其實我們要學習的就是這個兩個格式!客戶端傳送給伺服器的格式叫“請求協議”;伺服器傳送給客戶端的格式叫“響應協議”。
特點
- - HTTP叫超文字傳輸協議,基於請求/響應模式的!
- HTTP是無連線:無連線的含義是限制每次連線只處理一個請求。伺服器處理完客戶的請求,並收到客戶的應答後,即斷開連線。採用這種方式可以節省傳輸時間。
- HTTP是無狀態:HTTP協議是無狀態協議。無狀態是指協議對於事務處理沒有記憶能力。缺少狀態意味著如果後續處理需要前面的資訊,則它必須重傳,這樣可能導致每次連線傳送的資料量增大。另一方面,在伺服器不需要先前資訊時它的應答就較快。
URL:統一資源定位符,就是一個網址:協議名://域名:埠/路徑
2、HTTP請求協議
請求首行; // 請求方式 請求路徑 協議和版本,例如:GET /index.html HTTP/1.1
請求頭資訊;// 請求頭名稱:請求頭內容,即為key:value格式,例如:Host:localhost
空行; // 用來與請求體分隔開
請求體。 // GET沒有請求體,只有POST有請求體。
3、GET請求
HTTP預設的請求方法就是GET
特點
- - 沒有請求體
- - 資料必須在1K之內!
- - GET請求資料會暴露在瀏覽器的位址列中
GET請求常用的操作:
1. 在瀏覽器的位址列中直接給出URL,那麼就一定是GET請求
2. 點選頁面上的超連結也一定是GET請求
3. 提交表單時,表單預設使用GET請求,但可以設定為POST
如在一個網頁中右擊檢查點選network,可以看到一些請求資訊並作出一些解釋
GET 127.0.0.1:8080/login HTTP/1.1:GET請求,請求伺服器路徑為 127.0.0.1:8080/login ,協議為1.1;
Host:localhost:請求的主機名為localhost;
*User-Agent: Mozilla/5.0 (Windows NT 5.1; rv:5.0) Gecko/20100101 Firefox/5.0:與瀏覽器和OS相關的資訊。有些網站會顯示使用者的系統版本和瀏覽器版本資訊,這都是通過獲取User-Agent頭資訊而來的;
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8:告訴伺服器,當前客戶端可以接收的文件型別,其實這裡包含了*/*,就表示什麼都可以接收;
Accept-Language: zh-cn,zh;q=0.5:當前客戶端支援的語言,可以在瀏覽器的工具?選項中找到語言相關資訊;
Accept-Encoding: gzip, deflate:支援的壓縮格式。資料在網路上傳遞時,可能伺服器會把資料壓縮後再發送;
Accept-Charset: GB2312,utf-8;q=0.7,*;q=0.7:客戶端支援的編碼;
Connection: keep-alive:客戶端支援的連結方式,保持一段時間連結,預設為3000ms;
Cookie: JSESSIONID=369766FDF6220F7803433C0B2DE36D98:因為不是第一次訪問這個地址,所以會在請求中把上一次伺服器響應中傳送過來的Cookie在請求中一併傳送去過;這個Cookie的名字為JSESSIONID,然後在講會話是講究它!
4、 POST請求
特點:
1. 資料不會出現在位址列中
2. 資料的大小沒有上限
3. 有請求體
4. 請求體中如果存在中文,會使用URL編碼!
GET請求和POST請求的比較:
頁面使用GET,這樣載入速度比較快;
對於安全方式請求的用POST請求方式
5、響應協議
HTTP響應也由四個部分組成,分別是:狀態行、訊息報頭、空行和響應正文。
- HTTP/1.1 200 OK:響應協議為HTTP1.1,狀態碼為200,表示請求成功,OK是對狀態碼的解釋;
- Server:WSGIServer/0.2 CPython/3.5.2:伺服器的版本資訊;
- Content-Type: text/html;charset=UTF-8:響應體使用的編碼為UTF-8;
- Content-Length: 724:響應體為724位元組;
- Set-Cookie: JSESSIONID=C97E2B4C55553EAB46079A4F263435A4; Path=/hello:響應給客戶端的Cookie;
- Date: Wed, 25 Sep 2012 04:15:03 GMT:響應的時間,這可能會有8小時的時區差;
6、HTTP請求狀態碼
A、響應頭對瀏覽器來說很重要,它說明了響應的真正含義。例如200表示響應成功了,302表示重定向,這說明瀏覽器需要再發一個新的請求。
- 200:請求成功,瀏覽器會把響應體內容(通常是html)顯示在瀏覽器中;
- 404:請求的資源沒有找到,說明客戶端錯誤的請求了不存在的資源;
- 500:請求資源找到了,但伺服器內部出現了錯誤;
- 302:重定向,當響應碼為302時,表示伺服器要求瀏覽器重新再發一個請求,伺服器會發送一個響應頭Location,它指定了新請求的URL地址;
- 304:
當用戶第一次請求index.html時,伺服器會新增一個名為Last-Modified響應頭,這個頭說明了
index.html的最後修改時間,瀏覽器會把index.html內容,以及最後響應時間快取下來。當用戶第
二次請求index.html時,在請求中包含一個名為If-Modified-Since請求頭,它的值就是第一次請
求時伺服器通過Last-Modified響應頭髮送給瀏覽器的值,即index.html最後的修改時間,
If-Modified-Since請求頭就是在告訴伺服器,我這裡瀏覽器快取的index.html最後修改時間是這個,
您看看現在的index.html最後修改時間是不是這個,如果還是,那麼您就不用再響應這個index.html
內容了,我會把快取的內容直接顯示出來。而伺服器端會獲取If-Modified-Since值,與index.html
的當前最後修改時間比對,如果相同,伺服器會發響應碼304,表示index.html與瀏覽器上次快取的相
同,無需再次傳送,瀏覽器可以顯示自己的快取頁面,如果比對不同,那麼說明index.html已經做了修
改,伺服器會響應200。
B、其它響應頭
告訴瀏覽器不要快取的響應頭:
- Expires: -1;
- Cache-Control: no-cache;
- Pragma: no-cache;
自動重新整理響應頭,瀏覽器會在3秒之後請求http://www.baidu.com:
- Refresh: 3;url=http://www.baidu.com
C、HTML中指定響應頭
在HTMl頁面中可以使用<meta http-equiv="" content="">來指定響應頭,例如在index.html頁面中給出<meta http-equiv="Refresh" content="3;url=http://www.baidu.com">,表示瀏覽器只會顯示index.html頁面3秒,然後自動跳轉到http://www.baidu.com.
三、web伺服器
1、簡介
WEB伺服器也稱為WWW(WORLD WIDE WEB)伺服器,主要功能是提供網上資訊瀏覽服務。 WWW 是 Internet 的多媒體資訊查詢工具,是 Internet 上近年才發展起來的服務,也是發展最快和目前用的最廣泛的服務。正是因為有了WWW工具,才使得近年來 Internet 迅速發展,且使用者數量飛速增長
Web伺服器是指駐留於因特網上某種型別計算機的程式。當Web瀏覽器(客戶端)連到伺服器上並請求檔案時,伺服器將處理該請求並將檔案反饋到該瀏覽器上,附帶的資訊會告訴瀏覽器如何檢視該檔案(即檔案型別)。伺服器使用HTTP(超文字傳輸協議)與客戶機瀏覽器進行資訊交流,這就是人們常把它們稱為HTTP伺服器的原因。
2、HTTP協議
1. 應用層使用HTTP協議。
2. HTML(標準通用標記語言下的一個應用)文件格式。
3. 瀏覽器統一資源定位器(URL)。
4. 為了解決HTTP協議的這一缺陷,需要使用另一種協議:安全套接字層超文字傳輸協議HTTPS。為了資料傳輸的安全,HTTPS在HTTP的基礎上加入了SSL協議,SSL依靠證書來驗證伺服器的身份,併為瀏覽器和伺服器之間的通訊加密
四、WSGI
1、簡介
WSGI(Web Server Gateway Interface),是作為Web伺服器與Web應用程式或應用框架之間的一種低級別的介面,以提升可移植Web應用開發的共同點。WSGI是基於現存的CGI標準而設計的。
WSGI區分為兩個部分:一為“伺服器”或“閘道器”,
另一為“應用程式”或“應用框架”。
在處理一個WSGI請求時,伺服器會為應用程式提供環境資訊及一個回撥函式(Callback Function)。當應用程式完成處理請求後,通過前述的回撥函式,將結果回傳給伺服器。
2、應用
WSGI(Web Server Gateway Interface)是一種規範,它定義了使用python編寫的web app與web server之間介面格式,實現web app與web server間的解耦。
python標準庫提供的獨立WSGI伺服器稱為wsgiref
!/usr/bin/env python
# -*- coding:utf-8 -*-
# __Author__ Aaron
from wsgiref.simple_server import make_server
def application(request_info,response_info):
print(request_info) # 包裝了請求的諸多資訊
response_info('200 OK',[('Content-Type','text/html')]) # 反饋響應資訊
return [b'<h1>Hello World</h1>']
httpd = make_server("127.0.0.1", 8080, application)
# 開啟迴圈監聽http請求
自定製Web框架
通過python標準庫提供的獨立WSGI伺服器可以定製一個簡單的小型Web框架完整程式碼
from wsgiref.simple_server import make_server
import time
def fun1(req):
with open("index1.html","rb")as f:
data = f.read()
return data
def fun2(req):
with open("index2.html","rb")as f:
data = f.read()
return data
###################第1種##################
# def application(environ, start_response):
# #響應頭
# start_response('200 OK', [('Content-Type','text/html')])
#
# # print(environ)
# path = environ['PATH_INFO'] #取出路由
#
# if path == '/Aarom':
# # return [b'<h1>Hello, Aarom!</h1>']
# return [fun1()]
# elif path == '/Ping':
# # return [b'<h1>Hello, Peng!</h1>']
# return [fun2()]
# else:
# return [b'<h1>404</h1>']
#
# # 響應體
# # return [b'<h1>Hello, web!</h1>']
###################路由分發#################################
def login(req):
# print("req:", req['QUERY_STRING']) # req: user=2434&pwd=2233
return b'welcome!'
def signup(req):
pass
#增加一個時間顯示
def show_time(req):
times = time.ctime()
#靜態方法
# return ("<h1>time:%s</h1>" %str(times)).encode("utf-8")
# 動態載入html方法
with open("show_time.html", "rb") as f:
data = f.read()
data = data.decode("utf8")
data = data.replace("{{time}}",str(times))
return data.encode("utf8")
def router():
url_patterns=[
("/login",login),
("/signup",signup),
("/Aarom",fun1),
("/Ping",fun2),
("/show_time", show_time),
]
return url_patterns;
def application(environ, start_response):
#響應頭
start_response('200 OK', [('Content-Type','text/html')])
path = environ['PATH_INFO'] # 取出路由
# print(environ)
patterns = router();
func = None
for item in patterns:
if item[0] == path:
func = item[1]
break
if func:
return [func(environ)]
else:
return [b'<h1>404</h1>']
if __name__ == '__main__':
httpd = make_server('', 8080, application)
print('Serving HTTP on port 8080....')
httpd.serve_forever()
五、WEB伺服器,WEB框架,WSGI之間的關係
客戶端從傳送一個 HTTP 請求到 框架處理請求,分別經過了 web伺服器層,WSGI層,web框架層,這三個層次。不同的層次其作用也不同,下面簡要介紹各層的作用。
WEB伺服器層
對於傳統的客戶端 - 伺服器架構,其請求的處理過程是,客戶端向伺服器傳送請求,伺服器接收請求並處理請求,然後給客戶端返回響應。在這個過程中,伺服器的主要作用是:
- 接收請求
- 處理請求
- 返回響應
常見的 web伺服器有 Nginx,Apache,IIS等。在上圖1的三層結構中,web伺服器是最先接收使用者請求的,並將響應結果返回給使用者。
WEB框架層
Web框架的作用主要是方便我們開發 web應用程式,HTTP請求的動態資料就是由 web框架層來提供的。常見的 web框架有Flask,Django等
WSGI層
WSGI 不是伺服器,也不是用於與程式互動的API,更不是真實的程式碼,WSGI 只是一種介面,它只適用於 Python 語言,其全稱為 Web Server Gateway Interface,定義了 web伺服器和 web應用之間的介面規範。也就是說,只要 web伺服器和 web應用都遵守WSGI協議,那麼 web伺服器和 web應用就可以隨意的組合。
六、框架模型
A、MVC
MVC(Model View Controller 模型-檢視-控制器)是一種Web架構的模式
它把業務邏輯、模型資料、使用者介面分離開來,讓開發者將資料與表現解耦,前端工程師可以只改頁面效果部分而不用接觸後端程式碼,DBA可以重新命名資料表並且只需更改一個地方,無需從一大堆檔案中進行查詢和替換。MVC模式甚至還可以提高程式碼複用能力。現在幾乎所有的Web開發框架都建立在MVC模式之上。 當然,最近幾年也出現了一些諸如MVP, MVVM之類的新的設計模式。 但從技術的成熟程度和使用的廣泛程度來講,MVC仍是主流。
MVC三要素:
- Model(資料模型)。是對客觀事物的抽象。比如上篇我們說到的知乎Live,Live就是一個模型,可以用Live類來表示。而一個模型通常還帶有很多的和業務相關的邏輯,比如新增,更新,獲取Live主講人資訊等等,這些組成了模型的方法。對於開發者模型的表示方法非常易懂和清晰,可以通過非常便捷的程式碼來做CURD操作而無需寫一條又一條的SQL語句。
- View(檢視)。呈現給使用者的效果,呈現的內容是基於Model,它也是收集使用者輸入的地方。比如看到一篇Live,資料是一個Live.get(live_id).to_dict()的結果,效果是通過對應的模板和樣式把這個資料展示出來。
- Contorller(控制器)。是Model和View之間的溝通者。 因為View中不會對Model作任何操作,Model不會輸出任何用於表現的東西,如HTML程式碼或者某種效果等,它就是點資料。而Contorller用於決定使用哪些Model,對Model執行什麼操作,為檢視準備哪些資料,是MVC中溝通的橋樑。
B、 MTV
DJango的MTV模式MTV(Model Templates View 模型-模板-檢視)
- Model(資料模型)。和MVC的Model一樣,處理與資料相關的所有事務:如何存取、如何確認有效性、包含哪些行為以及資料之間的關係等。
- Template(模板)。處理與表現相關的決定:如何在頁面或其他型別文件中進行顯示出來。
- View。處理業務邏輯,檢視就是一個特定URL的回撥函式,回撥函式中描述資料:從Model取出對應的資料,呼叫相關的模板。它就是Contorller要呼叫的那個用來做Model和View之間的溝通函式,從而完成控制。
注意啦:MVC中的View的目的是「呈現哪一個資料」,而MTV的View的目的是「資料如何呈現」。
也就是把MVC中的View分成了檢視(展現哪些資料)和模板(如何展現)2個部分,而Contorller這個要素由框架自己來實現了,我們需要做的就是把(帶正則表示式的)URL對應到檢視就可以了,通過這樣的URL配置,系統將一個請求傳送到一個合適的檢視。