Python開發【第十四篇】:Web框架本質
Web框架本質
眾所周知,對於所有的Web應用,本質上其實就是一個socket服務端,用戶的瀏覽器其實就是一個socket客戶端。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
#!/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‘ , 8000 ))
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 等。不同的框架有不同的開發方式,但是無論如何,開發出的應用程序都要和服務器程序配合,才能為用戶提供服務。這樣,服務器程序就需要為不同的框架提供不同的支持。這樣混亂的局面無論對於服務器還是框架,都是不好的。對服務器來說,需要支持各種不同框架,對框架來說,只有支持它的服務器才能被開發出的應用使用。這時候,標準化就變得尤為重要。我們可以設立一個標準,只要服務器程序支持這個標準,框架也支持這個標準,那麽他們就可以配合使用。一旦標準確定,雙方各自實現。這樣,服務器可以支持更多支持標準的框架,框架也可以使用更多支持標準的服務器。
WSGI(Web Server Gateway Interface)是一種規範,它定義了使用python編寫的web app與web server之間接口格式,實現web app與web server間的解耦。
python標準庫提供的獨立WSGI服務器稱為wsgiref。
1 2 3 4 5 6 7 8 9 10 11 12 |
from wsgiref.simple_server import make_server
def RunServer(environ, start_response):
start_response( ‘200 OK‘ , [( ‘Content-Type‘ , ‘text/html‘ )])
return [bytes( ‘<h1>Hello, web!</h1>‘ , encoding = ‘utf-8‘ ), ]
if __name__ = = ‘__main__‘ :
httpd = make_server(‘‘, 8000 , RunServer)
print ( "Serving HTTP on port 8000..." )
httpd.serve_forever()
|
自定義Web框架
一、框架
通過python標準庫提供的wsgiref模塊開發一個自己的Web框架
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
#!/usr/bin/env python
#coding:utf-8
from wsgiref.simple_server import make_server
def index():
return ‘index‘
def login():
return ‘login‘
def routers():
urlpatterns = (
( ‘/index/‘ ,index),
( ‘/login/‘ ,login),
)
return urlpatterns
def RunServer(environ, start_response):
start_response( ‘200 OK‘ , [( ‘Content-Type‘ , ‘text/html‘ )])
url = environ[ ‘PATH_INFO‘ ]
urlpatterns = routers()
func = None
for item in urlpatterns:
if item[ 0 ] = = url:
func = item[ 1 ]
break
if func:
return func()
else :
return ‘404 not found‘
if __name__ = = ‘__main__‘ :
httpd = make_server(‘‘, 8000 , RunServer)
print "Serving HTTP on port 8000..."
httpd.serve_forever()
|
2、模板引擎
在上一步驟中,對於所有的login、index均返回給用戶瀏覽器一個簡單的字符串,在現實的Web請求中一般會返回一個復雜的符合HTML規則的字符串,所以我們一般將要返回給用戶的HTML寫在指定文件中,然後再返回。如:
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> </head> <body> <h1>Index</h1> </body> </html>
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> </head> <body> <form> <input type="text" /> <input type="text" /> <input type="submit" /> </form> </body> </html>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from wsgiref.simple_server import make_server
def index():
# return ‘index‘
f = open ( ‘index.html‘ )
data = f.read()
return data
def login():
# return ‘login‘
f = open ( ‘login.html‘ )
data = f.read()
return data
def routers():
urlpatterns = (
( ‘/index/‘ , index),
( ‘/login/‘ , login),
)
return urlpatterns
def run_server(environ, start_response):
start_response( ‘200 OK‘ , [( ‘Content-Type‘ , ‘text/html‘ )])
url = environ[ ‘PATH_INFO‘ ]
urlpatterns = routers()
func = None
for item in urlpatterns:
if item[ 0 ] = = url:
func = item[ 1 ]
break
if func:
return func()
else :
return ‘404 not found‘
if __name__ = = ‘__main__‘ :
httpd = make_server(‘‘, 8000 , run_server)
print "Serving HTTP on port 8000..."
httpd.serve_forever()
|
對於上述代碼,雖然可以返回給用戶HTML的內容以現實復雜的頁面,但是還是存在問題:如何給用戶返回動態內容?
- 自定義一套特殊的語法,進行替換
- 使用開源工具jinja2,遵循其指定語法
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> </head> <body> <h1>{{name}}</h1> <ul> {% for item in user_list %} <li>{{item}}</li> {% endfor %} </ul> </body> </html>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from wsgiref.simple_server import make_server
from jinja2 import Template
def index():
# return ‘index‘
# template = Template(‘Hello {{ name }}!‘)
# result = template.render(name=‘John Doe‘)
f = open ( ‘index.html‘ )
result = f.read()
template = Template(result)
data = template.render(name = ‘John Doe‘ , user_list = [ ‘alex‘ , ‘eric‘ ])
return data.encode( ‘utf-8‘ )
def login():
# return ‘login‘
f = open ( ‘login.html‘ )
data = f.read()
return data
def routers():
urlpatterns = (
( ‘/index/‘ , index),
( ‘/login/‘ , login),
)
return urlpatterns
def run_server(environ, start_response):
start_response( ‘200 OK‘ , [( ‘Content-Type‘ , ‘text/html‘ )])
url = environ[ ‘PATH_INFO‘ ]
urlpatterns = routers()
func = None
for item in urlpatterns:
if item[ 0 ] = = url:
func = item[ 1 ]
break
if func:
return func()
else :
return ‘404 not found‘
if __name__ = = ‘__main__‘ :
httpd = make_server(‘‘, 8000 , run_server)
print "Serving HTTP on port 8000..."
httpd.serve_forever()
|
遵循jinja2的語法規則,其內部會對指定的語法進行相應的替換,從而達到動態的返回內容,對於模板引擎的本質,參考另外一篇博客:白話tornado源碼之褪去模板外衣的前戲
Python開發【第十四篇】:Web框架本質