uvicorn簡介
uvicorn
是一個基於asyncio
開發的一個輕量級高效的web伺服器框架。
uvicorn
設計的初衷是想要實現兩個目標:
- 使用
uvloop
和httptools
實現一個極速的asyncio
伺服器。 - 實現一個基於
ASGI(非同步伺服器閘道器介面)
的最小的應用程式介面。
它目前支援http
,websockets
,Pub/Sub
廣播,並且可以擴充套件到其他協議和訊息型別。
安裝使用
uvicorn
僅支援python 3.5.3以上版本,我們可以通過pip3來快速的安裝。
Tip:建議和我一樣,直接使用pip3
來安裝,就不用關心繫統預設版本了。
➜ pip3 install uvicorn
...
Successfully installed gunicorn-19.7.1 httptools-0.0.10
uvicorn-0.0.15 uvloop-0.9.1 websockets-4.0.1
複製程式碼
安裝成功以後。就可以來編寫我們的伺服器應用程式碼了。
先建立一個應用檔案app.py
(名字可以自取)
在這個檔案中,來編寫一個簡單的伺服器應用。
1 # coding:utf-8
2
3 async def hello_world(message, channels):
4 content = b'<h1>Hello World</h1>'
5 resp = {
6 'status': 200,
7 'headers': [[b'content-type', b'text/html'],],
8 'content': content,
9 }
10 await channels['reply'].send(resp)
11
複製程式碼
寫好以後,先來嘗試執行一下,跑通了再看程式碼中具體內容的含義。
執行方式是: uvicorn 檔名:callable物件名
➜ uvicorn app:hello_world
複製程式碼
提示下面的內容就表示伺服器啟動成功了
(資訊中包括了訪問地址和埠號,以及worker執行的執行緒id)
[2018-02-26 00:48:52 +0800] [55984] [INFO] Starting gunicorn 19.7.1
[2018-02-26 00:48:52 +0800] [55984] [INFO] Listening at: http://127.0.0.1:8000 (55984)
[2018-02-26 00:48:52 +0800] [55984] [INFO] Using worker: uvicorn 0.0.15
[2018-02-26 00:48:52 +0800] [55987] [INFO] Booting worker with pid: 55987
複製程式碼
這時候我們在瀏覽器中訪問http://127.0.0.1:8000
,會看到網頁上顯示出 h1
號字型的Hello World
,也就是我們程式碼中定義的 content
的字串內容。
OK,伺服器跑起來了,接下來,我們來看一下程式碼是如何將內容返回給瀏覽器的。
介面分析
在程式碼中我們定義了一個協程函式,ASGI的協議要求應用應該對外暴露一個可接受 message
和 channels
這兩個引數的協程可呼叫物件(callable):
message
:一個ASGI訊息(但有區別,見下文)channels
:一個字典(<unicode string> : <channel interface>
)
<channel interface>
是具有以下屬性的物件:
- .send(message) 一個協程,用於傳送返回的訊息。可選
- .receive() 一個協程,用於接收進來的訊息。可選
- .name 一個
unicode
字串,channel的唯一標識。可選
uvicorn中的message
區別於ASGI中的訊息:
- 訊息還包括一個
channel
關鍵字,區別訊息型別,例如:'channel':'http.request'
- 訊息不包括例如
reply_channel
或body_channel
這樣的channel
名稱,,而是channels
字典可以檢視允許的channel
型別。
舉例:
傳進來的一個HTTP請求可能會是類似下面這樣的message
和 channels
.
message
{
'channel': 'http.request',
'scheme': 'http',
'root_path': '',
'server': ('127.0.0.1', 8000),
'http_version': '1.1',
'method': 'GET',
'path': '/',
'headers': [
[b'host', b'127.0.0.1:8000'],
[b'user-agent', b'curl/7.51.0'],
[b'accept', b'*/*']
]
}
複製程式碼
channels
{
'reply': <ReplyChannel>
}
複製程式碼
為了做出響應,應用程式需要向reply
的channel
傳送(.send()
)一個http響應,例如:
await channels['reply'].send({
'status': 200,
'headers': [
[b'content-type', b'text/plain'],
],
'content': b'Hello, world'
})
複製程式碼