web根源
眾所周知,對於所有的Web應用,本質上其實就是一個socket服務端,用戶的瀏覽器其實就是一個socket客戶端。
以下是一個最簡單的web程序

import socket # 最簡單的web程序 def handle_request(connection): connection.recv(1024) connection.send(bytes("HTTP/1.1 200 OK\r\n\r\n".encode("utf-8"))) connection.send(bytes("hello, kelly 我是中國人!!".encode("utf-8"))) def service(): server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server_address = ('127.0.0.1', 8000) server.bind(server_address) server.listen(5) while True: connection, client_address = server.accept() print(connection) handle_request(connection) connection.close() if __name__ == '__main__': service()
執行 python basic_server.py
在瀏覽器中輸入http://127.0.0.1:8000/login
顯示:
hello, kelly 我是中國人!!
注意send中需要byte參數,而不是str。
無論瀏覽器中輸入什么路徑,我們得到的結果都一樣
wsgi
上述通過socket來實現了其本質,而對於真實開發中的python web程序來說,一般會分為兩部分:服務器程序和應用程序。服務器程序負責對socket服務器進行封裝,並在請求到來時,對請求的各種數據進行整理。應用程序則負責具體的邏輯處理。為了方便應用程序的開發,就出現了眾多的Web框架,例如:Django、Flask、web.py 等。不同的框架有不同的開發方式,但是無論如何,開發出的應用程序都要和服務器程序配合,才能為用戶提供服務。這樣,服務器程序就需要為不同的框架提供不同的支持。這樣混亂的局面無論對於服務器還是框架,都是不好的。對服務器來說,需要支持各種不同框架,對框架來說,只有支持它的服務器才能被開發出的應用使用。這時候,標准化就變得尤為重要。我們可以設立一個標准,只要服務器程序支持這個標准,框架也支持這個標准,那么他們就可以配合使用。一旦標准確定,雙方各自實現。這樣,服務器可以支持更多支持標准的框架,框架也可以使用更多支持標准的服務器。
WSGI(Web Server Gateway Interface)是一種規范,它定義了使用python編寫的web app與web server之間接口格式,實現web app與web server間的解耦。
python標准庫提供的獨立WSGI服務器稱為wsgiref。

from wsgiref.simple_server import make_server # 所有的地址返回的結果都一樣 def application(environ, start_response): start_response('200 OK', [('Content-Type', 'text/html')]) return [bytes('<h1>Hello, kelly!</h1>'.encode("utf-8")), b'abc'] def run_server(): server = make_server("127.0.0.1", 8000, application) server.serve_forever() if __name__ == '__main__': run_server()
路徑分發
上述程序有個致命的缺點,不同的url返回相同的內容。現在改成針對不同的url來返回不同的內容

from wsgiref.simple_server import make_server # 不同的網址有不同的結果,但是所有的處理邏輯寫到一起,很混亂 def application(environ, start_response): url = environ['PATH_INFO'] print("url:", url) start_response('200 OK', [('Content-Type', 'text/html')]) if url == "/index": return [bytes('<h1>index!</h1>'.encode("utf-8")), b'abc'] elif url == "/login": return [bytes('<h1>login !</h1>'.encode("utf-8")), b'abc'] elif url == "/logout": return [bytes('<h1>logout !</h1>'.encode("utf-8")), b'abc'] else: return [bytes('<h1>404 !</h1>'.encode("utf-8")), b'abc'] def run_server(): server = make_server("127.0.0.1", 8000, application) server.serve_forever() if __name__ == '__main__': run_server()
environ['PATH_INFO']目的是取得輸入的url中的路徑
url_server僅僅使用了if語句,針對幾個不同的路徑得到了不同的返回值。要做到路徑五花八門,返回值多樣,還需要對程序進行進一步的解耦

from wsgiref.simple_server import make_server def index(): return [bytes('<h1>index!</h1>'.encode("utf-8")), b'abc'] def login(): return [bytes('<h1>login !</h1>'.encode("utf-8")), b'abc'] def logout(): return [bytes('<h1>logout !</h1>'.encode("utf-8")), b'abc'] urlConf = [ ("/index", index), ("/login", login), ("/logout", logout), ] # 不同的網址有不同的結果,但是所有的處理邏輯寫到一起,很混亂 def application(environ, start_response): url = environ['PATH_INFO'] print("url:", url) response_fun = None for item in urlConf: if url == item[0]: response_fun = item[1] break if response_fun: start_response('200 OK', [('Content-Type', 'text/html')]) response_body = response_fun() else: start_response('404 Not Found', [('Content-Type', 'text/html')]) response_body = [bytes('<h1>404 !</h1>'.encode("utf-8")), b'abc'] return response_body def run_server(): server = make_server("127.0.0.1", 8000, application) server.serve_forever() if __name__ == '__main__': run_server()
urlConf用戶根據不同的路徑,配置不同的函數。
server程序中遍歷urlConf來根據路徑定位所要執行的函數。
這程序的缺點:所有的功能都寫到一個py文件中,顯得很混亂。
mtv
我們可以分成三個文件
view.py:專門用戶存放各種頁面的處理函數
url.py 配置路徑和函數的關系
server.py 執行web的主程序
將不同功能的代碼分門別類存放,目的是解耦。
M model 與數據庫處理有關的程序
T template 各種html程序
V url的處理函數
以上僅僅是python web的簡單了解,若想深入了解,請研究wsgi、多線程等。