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 等。不同的框架有不同的開發方式,但是無論如何,開發出的應用程序都要和服務器程序配合,才能為用戶提供服務。這樣,服務器程序就需要為不同的框架提供不同的支持。這樣混亂的局面無論對于服務器還是框架,都是不好的。對服務器來說,需要支持各種不同框架,對框架來說,只有支持它的服務器才能被開發出的應用使用。這時候,標準化就變得尤為重要。我們可以設立一個標準,只要服務器程序支持這個標準,框架也支持這個標準,那么他們就可以配合使用。一旦標準確定,雙方各自實現。這樣,服務器可以支持更多支持標準的框架,框架也可以使用更多支持標準的服務器。
js框架都有哪些,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 13 | #!/usr/bin/env python #coding:utf-8 from ?wsgiref.simple_server? import ?make_server def ?RunServer(environ, start_response): ???? start_response( '200 OK' , [( 'Content-Type' ,? 'text/html' )]) ???? return ?'<h1>Hello, web!</h1>' 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() |
html5框架?對于上述代碼,雖然可以返回給用戶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源碼之褪去模板外衣的前戲
?