日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > python >内容正文

python

Web基础(三)Python Web

發布時間:2023/12/8 python 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Web基础(三)Python Web 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

  • Python Web基礎
    • 1. WSGI
      • 1.1 概述
      • 1.2 實現原理
        • 1、WSGI Server/gateway
        • 2、WSGI Application
        • 3、WSGI MiddleWare
      • 1.3 測試 WSGI服務器
        • 代碼簡析
      • 1.4 實現WSGI服務器
      • 1.5 生產環境中的Web服務器
        • [Gunicorn](https://github.com/benoitc/gunicorn "Gunicorn")
        • [uWSGI ](https://github.com/unbit/uwsgi-docs "uWSGI ")
        • [bjoern](https://github.com/jonashaag/bjoern#libev "bjoern")
    • 2. Web應用開發
      • 2.1 服務器架構
        • 2.1.1 Nginx
          • 反向代理
          • Nginx的優勢
    • 附錄

Python Web基礎

Web應用的本質:
1. 瀏覽器發送一個HTTP請求
2. 服務器收到請求,生成一個HTML文檔
3. 服務器把HTML文檔作為HTTP響應的Body發送給瀏覽器
4. 瀏覽器收到HTTP響應,從HTTP Body取出HTML文檔并顯示

所以,最簡單的Web應用就是先把HTML用文件保存好,用一個現成的HTTP服務器軟件,接收用戶請求,從文件中讀取HTML,返回。我們上兩篇博客已經詳細講解并實現了這樣的HTTP服務器zjhttp,除此外Apache、Nginx、Lighttpd等這些常見的靜態服務器就是干這件事情的。

如果要動態生成HTML,就需要把上述步驟自己來實現。不過,接受HTTP請求、解析HTTP請求、發送HTTP響應都是苦力活,如果我們自己來寫這些底層代碼,還沒開始寫動態HTML呢,就得花個把月去讀HTTP規范。正確的做法是底層代碼由專門的服務器軟件實現,我們用Python專注于生成HTML文檔。

1. WSGI

Web服務器網關接口(Python Web Server Gateway Interface,縮寫為WSGI)是為Python語言定義的Web服務器和Web應用程序或框架之間的一種簡單而通用的接口。自從WSGI被開發出來以后,許多其它語言中也出現了類似接口。

以前,如何選擇合適的Web應用程序框架成為困擾Python初學者的一個問題,這是因為,一般而言,Web應用框架的選擇將限制可用的Web服務器的選擇,反之亦然。那時的Python應用程序通常是為CGI,FastCGI,mod_python中的一個而設計,甚至是為特定Web服務器的自定義的API接口而設計的。

WSGI(有時發音作’wiz-gee’)是作為Web服務器與Web應用程序或應用框架之間的一種低級別的接口,以提升可移植Web應用開發的共同點。WSGI是基于現存的CGI標準而設計的。WSGI沒有官方的實現, 因為WSGI更像一個協議。只要遵照這些協議,WSGI應用(Application)都可以在任何服務器(Server)上運行, 反之亦然。WSGI就是Python的CGI包裝,相對于Fastcgi是PHP的CGI包裝

1.1 概述

WSGI區分為兩個部分
1. 為“服務器”或“網關”。它用于接收、整理客戶端發送的請求
2. 為“應用程序”或“應用框架”。處理服務器程序傳遞過來的請求

如上圖,Web服務器即第一部分,接收、整理客戶端發送的請求,咱們前兩篇博客使用C語言實現的zjhttp就是屬于Web服務器部分;Web框架即為第二部分,即所謂的Web應用程序。開發Web應用程序的時候,通常會把常用的功能封裝起來,成為各種框架,比如Flask,Django,Tornado(使用某框架進行web開發,相當于開發服務端的應用程序,處理后臺邏輯)。但是,服務器程序和應用程序互相配合才能給用戶提供服務,而不同應用程序(不同框架)會有不同的函數、功能。 此時,我們就需要一個標準,讓服務器程序和應用程序都支持這個標準,那么,二者就能很好的配合了,這個標準就是 WSGI

在處理一個WSGI請求時,服務器會為應用程序提供環境信息及一個回調函數(Callback Function)。當應用程序完成處理請求后,透過前述的回調函數,將結果回傳給服務器。

所謂的 WSGI 中間件同時實現了API的兩方,因此可以在WSGI服務器和WSGI應用之間起調解作用。從Web服務器的角度來說,中間件扮演應用程序,而從應用程序的角度來說,中間件扮演服務器。“中間件”組件可以執行以下功能:
1. 重寫環境變量后,根據目標URL,將請求消息路由到不同的應用對象。
2. 允許在一個進程中同時運行多個應用程序或應用框架。
3. 負載均衡和遠程處理,通過在網絡上轉發請求和響應消息。
4. 進行內容后處理,例如應用XSLT樣式表。

1.2 實現原理

WSGI 將 Web 組件分為三類

  • web服務器
  • web中間件
  • web應用程序

wsgi基本處理模式為:
WSGI Server -> WSGI Middleware -> WSGI Application

1、WSGI Server/gateway

wsgi server可以理解為一個符合wsgi規范的web server,接收request請求,封裝一系列環境變量,按照wsgi規范調用注冊的wsgi app,最后將response返回給客戶端。以python自帶的wsgiref為例,wsgiref是按照wsgi規范實現的一個簡單wsgi server。它的代碼不復雜。

  • 服務器創建socket,監聽端口,等待客戶端連接。
  • 當有請求來時,服務器解析客戶端信息放到環境變量environ中,并調用綁定的handler來處理請求。
  • handler解析這個http請求,將請求信息例如method,path等放到environ中。
  • wsgi handler再將一些服務器端信息也放到environ中,最后服務器信息,客戶端信息,本次請求信息全部都保存到了環境變量environ中。
  • wsgi handler 調用注冊的wsgi app,并將environ和回調函數傳給wsgi app
  • wsgi app 將reponse header/status/body 回傳給wsgi handler
  • 最終handler還是通過socket將response信息塞回給客戶端。
  • 2、WSGI Application

    wsgi application就是一個普通的callable對象,當有請求到來時,wsgi server會調用這個wsgi app。這個對象接收兩個參數,通常為environ,start_response。environ就像前面介紹的,可以理解為環境變量,跟一次請求相關的所有信息都保存在了這個環境變量中,包括服務器信息,客戶端信息,請求信息。start_response是一個callback函數,wsgi application通過調用start_response,將response headers/status 返回給wsgi server。此外這個wsgi app會return 一個iterator對象 ,這個iterator就是response body。這么空講感覺很虛,對著下面這個簡單的例子看就明白很多了。

    3、WSGI MiddleWare

    有些功能可能介于服務器程序和應用程序之間,例如,服務器拿到了客戶端請求的URL, 不同的URL需要交由不同的函數處理,這個功能叫做 URL Routing,這個功能就可以放在二者中間實現,這個中間層就是 middleware。middleware對服務器程序和應用是透明的,也就是說,服務器程序以為它就是應用程序,而應用程序以為它就是服務器。這就告訴我們,middleware需要把自己偽裝成一個服務器,接受應用程序,調用它,同時middleware還需要把自己偽裝成一個應用程序,傳給服務器程序。

    論是服務器程序、middleware 還是應用程序,都在服務端,為客戶端提供服務,之所以把他們抽象成不同層,就是為了控制復雜度,使得每一次都不太復雜,各司其職。

    1.3 測試 WSGI服務器

    原理說得太多未免過于抽象,現在使用Python內置的純Python代碼編寫的wsgiref服務器來體驗一把WSGI服務器是如何工作的

    • 編寫hello.py 作為一個Web應用程序

      def application(environ, start_response):start_response('200 OK', [('Content-Type', 'text/html')])return [b'<h1>Hello, World!</h1>']
    • 編寫server.py作為一個WSGI服務器

      from wsgiref.simple_server import make_server # 導入編寫的application函數 from hello import application# 創建一個服務器,IP地址為空,端口是8000,傳入函數application httpd = make_server('', 8000, application) print('Serving HTTP on port 8000...') # 開始監聽HTTP請求: httpd.serve_forever()
    • 啟動WSGI服務器

      python server.py
    • 使用客戶端訪問
      打開瀏覽器,輸入http://localhost:8000/ ,在瀏覽器正常顯示“Hello, World!”

    代碼簡析

    上面的application()函數就是符合WSGI標準的一個HTTP處理函數,它接收兩個參數:

    • environ:一個包含所有HTTP請求信息的dict對象
    • start_response:一個發送HTTP響應的函數

    而在application()函數中又調用了start_response函數

    該函數發送了HTTP響應的Header,注意Header只能發送一次,也就是只能調用一次start_response()函數。start_response()函數接收兩個參數,一個是HTTP響應碼,一個是一組list表示的HTTP Header,每個Header用一個包含兩個str的tuple表示。

    通常情況下,都應該把Content-Type頭發送給瀏覽器。其他很多常用的HTTP Header也應該發送。然后,函數的返回值b'<h1>Hello, web!</h1>'將作為HTTP響應的Body發送給瀏覽器。

    有了WSGI,我們關心的就是如何從environ這個dict對象拿到HTTP請求信息,然后構造HTML,通過start_response()發送Header,最后返回Body。

    整個application()函數本身沒有涉及到任何解析HTTP的部分,也就是說,底層代碼不需要我們自己編寫,我們只負責在更高層次上考慮如何響應請求就可以了。

    需要注意的是,application()函數必須由WSGI服務器來調用。有很多符合WSGI規范的服務器,我們可以挑選一個來用。但是我們僅將內置的wsgiref服務器用于測試,使我們編寫的Web應用程序立馬跑起來。

    1.4 實現WSGI服務器

    為了了解wsgi的工作原理,我們可以參照wsgiref源碼,使用Python簡單實現一個WSGI服務器

    import socket import StringIO import sysclass WSGIServer(object):address_family = socket.AF_INETsocket_type = socket.SOCK_STREAMrequest_queue_size = 1def __init__(self, server_address):# 創建socket,利用socket獲取客戶端的請求self.listen_socket = listen_socket = socket.socket(self.address_family, self.socket_type)# 設置socket的工作模式listen_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)# 綁定socket地址listen_socket.bind(server_address)# socket active, 監聽文件描述符listen_socket.listen(self.request_queue_size)# 獲得serve的host name和porthost, port = self.listen_socket.getsockname()[:2]self.server_name = socket.getfqdn(host)self.server_port = portself.headers_set = []def set_app(self, application):self.application = application #啟動WSGI server服務,不停的監聽并獲取socket數據。def serve_forever(self):listen_socket = self.listen_socketwhile True:self.client_connection, client_address = listen_socket.accept() #接受客戶端請求#處理請求self.handle_one_request()def handle_one_request(self):self.request_data = request_data = self.client_connection.recv(1024)self.parse_request(request_data)# Construct environment dictionary using request dataenv = self.get_environ()#給flask\tornado傳遞兩個參數,environ,start_responseresult = self.application(env, self.start_response)self.finish_response(result)#處理socket的http協議def parse_request(self, data):format_data = data.splitlines()if len(format_data):request_line = data.splitlines()[0]request_line = request_line.rstrip('\r\n')(self.request_method, self.path, self.request_version) = request_line.split() ## ['GET', '/', 'HTTP/1.1']# 獲取environ數據并設置當前server的工作模式def get_environ(self):env = {}env['wsgi.version'] = (1, 0)env['wsgi.url_scheme'] = 'http'env['wsgi.input'] = StringIO.StringIO(self.request_data)env['wsgi.errors'] = sys.stderrenv['wsgi.multithread'] = Falseenv['wsgi.multiprocess'] = Falseenv['wsgi.run_once'] = False# Required CGI variablesenv['REQUEST_METHOD'] = self.request_method # GETenv['PATH_INFO'] = self.path # /helloenv['SERVER_NAME'] = self.server_name # localhostenv['SERVER_PORT'] = str(self.server_port) # 8888return envdef start_response(self, status, response_headers, exc_info=None):server_headers = [('Date', 'Tue, 31 Mar 2015 12:54:48 GMT'), ('Server', 'WSGIServer 0.2')]self.headers_set = [status, response_headers + server_headers]#把application返回給WSGI的數據返回給客戶端。def finish_response(self, result):try:status, response_headers = self.headers_setresponse = 'HTTP/1.1 {status}\r\n'.format(status=status)for header in response_headers:response += '{0}: {1}\r\n'.format(*header)response += '\r\n'for data in result:response += dataself.client_connection.sendall(response)print(''.join(['> {line}\n'.format(line=line) for line in response.splitlines()]))finally:self.client_connection.close()SERVER_ADDRESS = (HOST, PORT) = '', 8888def make_server(server_address, application):server = WSGIServer(server_address)server.set_app(application)return serverif __name__ == '__main__':if len(sys.argv) < 2:sys.exit('Provide a WSGI application object as module:callable')app_path = sys.argv[1]module, application = app_path.split(':') # 第一個參數是文件名,第二個參數時長文件內app的命名module = __import__(module)application = getattr(module, application) # getattr(object, name[, default]) -> valuehttpd = make_server(SERVER_ADDRESS, application)print('WSGIServer: Serving HTTP on port {port} ...\n'.format(port=PORT))httpd.serve_forever()

    1.5 生產環境中的Web服務器

    每個web框架都不是專注于實現服務器方面的,因此,在生產環境部署的時候,使用的服務器也不會簡單的使用web框架自帶的服務器,那么用于生產環境的服務器有哪些呢?

    Gunicorn

    Gunicorn(從Ruby下面的Unicorn得到的啟發)應運而生:依賴Nginx的代理行為,同Nginx進行功能上的分離。由于不需要直接處理用戶來的請求(都被Nginx先處理),Gunicorn不需要完成相關的功能,其內部邏輯非常簡單:接受從Nginx來的動態請求,處理完之后返回給Nginx,由后者返回給用戶。

    由于功能定位很明確,Gunicorn得以用純Python開發:大大縮短了開發時間的同時,性能上也不會很掉鏈子。同時,它也可以配合Nginx的代理之外的別的Proxy模塊工作,其配置也相應比較簡單

    uWSGI

    使用C語言開發,和底層接觸的更好,配置也比較方便,目前和gunicorn兩個算是部署時的唯二之選。由于其可擴展的架構,它能夠被無限制的擴展用來支持更多的平臺和語言。目前,可以使用C,C++和Objective-C來編寫插件

    uWSGI 既不使用wsgi協議也不用FastCGI協議,而是自創了一個uwsgi的協議,uwsgi協議是一個uWSGI服務器自有的協議,它用于定義傳輸信息的類型(type of information),每一個uwsgi packet前4byte為傳輸信息類型描述,它與WSGI相比是兩樣東西。據說該協議大約是fcgi協議的10倍那么快

    主要特點如下:

    • 超快的性能
    • 低內存占用(實測為apache2的mod_wsgi的一半左右)
    • 多app管理
    • 詳盡的日志功能(可以用來分析app性能和瓶頸)
    • 高度可定制(內存大小限制,服務一定次數后重啟等)

    uWSGI 服務器自己實現了基于uwsgi協議的server部分,因此我們只需要在uwsgi的配置文件中指定application的地址,uWSGI 就能直接和應用框架中的WSGI application通信

    bjoern

    是一個用C語言編寫的,快速超輕量級的 Python WSGI服務器。
    它是最快速的,最小的并且是最輕量級的WSGI服務器。有以下特性:

    • 1000 行的C代碼
    • 占用內存 600KB
    • 單線程沒有其他協同程序
    • 可以綁定到TCP主機:端口地址和Unix套接字
    • 支持HTTP1.0/1.1,包含支持HTTP1.1的分塊響應

    如果單純追求性能,那uWSGI會更好一點,而Gunicorn則會更易安裝和結合gevent。在阻塞響應較多的情況下,Gunicorn的gevent模式無疑性能會更加強大。功能實現方面,uWSGI會更多一些,配置也會更加復雜一些。

    2. Web應用開發

    常見的Python Web應用框架:

    • Django:全能型Web框架
    • Flask:一個使用Python編寫的輕量級Web框架
    • web.py:一個小巧的Web框架
    • Bottle:和Flask類似的Web框架
    • Tornado:Facebook的開源異步Web框架

    2.1 服務器架構

    2.1.1 Nginx

    Nginx(發音同engine x)是一個異步框架的 Web服務器,也可以用作反向代理,負載平衡器 和 HTTP緩存。該軟件由 Igor Sysoev 創建,并于2004年首次公開發布。同名公司成立于2011年,以提供支持。

    Nginx是一款免費的開源軟件,根據類BSD許可證的條款發布。一大部分Web服務器使用Nginx,通常作為負載均衡器。

    Nginx是一款面向性能設計的HTTP服務器,相較于Apache、lighttpd具有占有內存少,穩定性高等優勢。與舊版本(<=2.2)的Apache不同,Nginx不采用每客戶機一線程的設計模型,而是充分使用異步邏輯從而削減了上下文調度開銷,所以并發服務能力更強。整體采用模塊化設計,有豐富的模塊庫和第三方模塊庫,配置靈活。 在Linux操作系統下,Nginx使用epoll事件模型,得益于此,Nginx在Linux操作系統下效率相當高。同時Nginx在OpenBSD或FreeBSD操作系統上采用類似于epoll的高效事件模型kqueue。

    Nginx在官方測試的結果中,能夠支持五萬個并行連接,而在實際的運作中,可以支持二萬至四萬個并行連接

    反向代理

    正向代理是指瀏覽器主動請求代理服務器,代理服務器轉發請求到對應的目標服務器。而反向代理則部署在Web服務器上,代理所有外部網絡對內部網絡的訪問。瀏覽器訪問服務器,必須經過這個代理,是被動的。正向代理的主動方是客戶端,反向代理的主動方是Web服務器

    在Python的Web開發中,較為成熟穩定的服務器架構一般是Nginx + uWSGI + Django。而實際上Nginx服務器并不是必須的,直接使用uWSGI + Djang完全是可以的,但這樣一來,直接將uWSGI服務器暴露給了瀏覽器客戶端,由此會導致諸多隱患。

    Nginx的優勢
  • 安全問題。客戶端對Web服務器的訪問需要先經過反向代理服務器,Nginx則只需開放某個接口,uWSGI本身是內網接口,這樣可以防止外部程序對Web服務器的直接攻擊。
  • 負載均衡。反向代理服務器可以根據Web服務器的負載情況,動態地把HTTP請求交給不同的Web服務器來處理,前提是要有多個Web服務器。
  • 提升Web服務器的IO性能。一個HTTP請求的數據,從客戶端傳輸給服務器,是需要時間的,例如N秒,如果直接傳給Web服務器,Web服務器就需要讓一個進程阻塞N秒,來接收IO,這樣會降低Web服務器的性能。如果使用Nginx作為反向代理服務器,先讓反向代理服務器接收完整個HTTP請求,再把請求發給Web服務器,就能提升Web服務器的性能。將靜態資源發送(js、css、圖片等)、動態請求轉發以及結果的回復交給Nginx處理,就不需要經過Web服務器。

  • 附錄

    支持WSGI的Web應用框架有很多

    • BlueBream
    • bobo
    • Bottle
    • CherryPy
    • Django
    • Flask
    • Google App Engine’s webapp2
    • Gunicorn
    • prestans
    • Pylons
    • Pyramid
    • restlite
    • Tornado
    • Trac
    • TurboGears
    • Uliweb
    • web.py
    • web2py
    • weblayer
    • Werkzeug

    參考

    [參考資料1]
    [參考資料2]
    [參考資料3]
    [參考資料4]
    [參考資料5]

    總結

    以上是生活随笔為你收集整理的Web基础(三)Python Web的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。