eventlet 的 wsgi 模塊提供了一種啟動事件驅動的WSGI服務器的簡潔手段,可以將其作為某個應用的嵌入web服務器,或作為成熟的web服務器,一個這樣的web服務器的例子就是 Spawning。
目錄
2. eventlet.wsgi.format_data_time()
要啟動一個 wsgi 服務器,只需要創建一個套接字,然后用它調用 eventlet.wsgi.server() 就可以。
例如:
from eventlet import wsgi import eventlet def hello_world(env, start_response): start_response('200 OK', [('Content-Type', 'text/plain')]) return ['Hello, World!\r\n'] wsgi.server(eventlet.listen(('', 8090)), hello_world)
這個簡單的 server 使用 eventlet.listen() 創建了一個套接字,wsgi.server() 監聽對應的地址、端口等,將請求傳遞給 WSGI 應用 hello_world 處理。
一個稍微形象一些的例子如下:
import eventlet from eventlet import wsgi def hello_world(env, start_response): if env['PATH_INFO'] != '/': start_response('404 Not Found', [('Content-Type', 'text/plain')]) return ['Not Found\r\n'] start_response('200 OK', [('Content-Type', 'text/plain')]) return ['Hello, World!\r\n'] wsgi.server(eventlet.listen(('', 8090)), hello_world)
這個例子非常簡潔地詮釋了 WSGI 的應用接口規范,也涵蓋了 eventlet.wsgi 模塊中起 server 的用法。
eventlet.wsgi.server()
eventlet.wsgi.server( socket, site, log=None, environ=None, max_size=None, max_http_version='HTTP/1.1', protocol=<class eventlet.wsgi.HttpProtocol at 0x7f4f68192f58>, server_event=None, minimum_chunk_size=None, log_x_forwarded_for=True, custom_pool=None, keepalive=True, log_output=True, log_format='%(client_ip)s - - [%(date_time)s] "%(request_line)s" %(status_code)s %(body_length)s %(wall_seconds).6f', url_length_limit=8192, debug=True, socket_timeout=None, capitalize_response_headers=True)
這個調用封裝了很多功能,創建一個 WSGI server 來處理指定套接字中產生的請求,這個函數會一直循環下去,即時刻監聽請求。當 server 退出時,對應的套接字對象 socket 也會被關閉但是底層的文件描述字會被保留,所以這個時候如果用這個 socket 調用 dup() ,將會仍然可以使用。
參數:
socket | Server socket, 已經綁定一個端口且監聽中 |
site | 實現 WSGI 應用的函數 |
log |
日志輸出的位置,應該是一個類文件(file-like)對象,缺省為 sys.stderr |
environ | 添加到每一次請求的 environ 字典中的額外參量 |
max_size | 這個 server 時刻允許的最大客戶端連接數 |
max_http_version | 設為 “HTTP/1.0” 會只支持 HTTP 1.0. 可以支持那些在 HTTP 1.1 下並不能正常工作的應用 |
protocol | 棄用,協議類 |
server_event | 棄用,用來收集 Server 對象 |
minimum_chunk_size | 以字節記的HTTP塊的最小尺寸。 可以用來改進哪些產生很多小字串的應用的性能。盡管使用它在技術上違背 WSGI 規范,但可以通過設置environ[‘eventlet.minimum_write_chunk_size’]來在每次請求的程度上覆寫 |
log_x_forwarded_for | 如果為 True (缺省), 除了在日志的 ‘client_ip’ 段記錄實際的客戶端 ip 地址外,還記錄HTTP頭中的 x-forwarded-for 的內容 |
custom_pool | 一個定制的 GreenPool 實例,用來孵化客戶端的 greenthreads. 如果設置了該項,無視參數 max_size |
keepalive | 設為False 會禁止 server keepalives,所有的連接都會在服務完一個請求后關閉 |
log_output | Boolean 值,指示 server 是否記錄日志 |
log_format | A python format string that is used as the template to generate log lines. The following values can be formatted into it: client_ip, date_time, request_line, status_code, body_length, wall_seconds. The default is a good example of how to use it |
url_length_limit | 請求URL的最大長度,如果超長,返回414錯誤 |
debug | 如果想要服務器將異常追溯信息子啊500錯誤中發回給客戶端,這里就設置為True。 如果這里設置為 False,server 將會響應空值 |
socket_timeout | 客戶端連接的套接字操作超時限制,缺省為 None,意味着永久等待 |
capitalize_response_headers | 大寫響應頭的字段名稱,缺省為True |
eventlet.wsgi.format_date_time(timestamp)
將Unix時間戳格式化為一個 HTTP 標准字符串。
要創建一個安全的 server ,只需要傳入一個 SSL 包裹的套接字即可:
wsgi.server(eventlet.wrap_ssl( eventlet.listen(('', 8090)), certfile='cert.crt', keyfile='private.key', server_side=True), hello_world)
應用可以通過環境變量 env['wsgi.url_scheme'] 判斷自己是不是在一個SSL server中。
Eventlet 的 WSGI server 支持對於 WSGI 規范的非標准擴展——用 env['eventlet.posthooks'] 包含一個有若干post hooks 的數組,這些 post hooks 會在完全發送完響應后被調用。每一個 post hook 是一個格式為 (func, args, kwargs) 的元組,以 WSGI environment 字典加 args 和 kwargs 為參數調用 func。
例如:
from eventlet import wsgi import eventlet def hook(env, arg1, arg2, kwarg3=None, kwarg4=None): print('Hook called: %s %s %s %s %s' % (env, arg1, arg2, kwarg3, kwarg4)) def hello_world(env, start_response): env['eventlet.posthooks'].append( (hook, ('arg1', 'arg2'), {'kwarg3': 3, 'kwarg4': 4})) start_response('200 OK', [('Content-Type', 'text/plain')]) return ['Hello, World!\r\n'] wsgi.server(eventlet.listen(('', 8090)), hello_world)
上面的代碼會為每一個處理的請求打印 WSGI 環境和其他的函數參數。
當需要在完全響應一個客戶端請求后(或客戶端過早地斷開連接后)執行一段代碼時 Post hook 非常有用。 一個例子就是精確記錄帶寬的使用情況,因為用戶斷開連接時消耗的帶寬小於 Content-Length 中標出的值。
Eventlet 的 WSGI server 支持發送(可選的)headers 和 HTTP “100 Continue” 臨時響應. This is useful in such cases where a WSGI server expects to complete a PUT request as a single HTTP request/response pair, and also wants to communicate back to client as part of the same HTTP transaction. An example is where the HTTP server wants to pass hints back to the client about characteristics of data payload it can accept. As an example, an HTTP server may pass a hint in a header the accompanying “100 Continue” response to the client indicating it can or cannot accept encrypted data payloads, and thus client can make the encrypted vs unencrypted decision before starting to send the data).
This works well for WSGI servers as the WSGI specification mandates HTTP expect/continue mechanism (PEP333).
要定義 “100 Continue” 響應頭, 需要調用 env['wsgi.input'] 里的 set_hundred_continue_response_header() 如下:
from eventlet import wsgi import eventlet def wsgi_app(env, start_response): # Define "100 Continue" response headers env['wsgi.input'].set_hundred_continue_response_headers( [('Hundred-Continue-Header-1', 'H1'), ('Hundred-Continue-Header-k', 'Hk')]) # The following read() causes "100 Continue" response to # the client. Headers 'Hundred-Continue-Header-1' and # 'Hundred-Continue-Header-K' are sent with the response # following the "HTTP/1.1 100 Continue\r\n" status line text = env['wsgi.input'].read() start_response('200 OK', [('Content-Length', str(len(text)))]) return [text]