[Python]Uvicorn初體驗

原文鏈接:http://vimiix.com/post/2018/02/26/first-practise-of-uvicorn/

uvicorn簡介

uvicorn是一個基於asyncio開發的一個輕量級高效的web服務器框架。

官網:http://www.uvicorn.org

uvicorn 設計的初衷是想要實現兩個目標:

它目前支持httpwebsocketsPub/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的協議要求應用應該對外暴露一個可接受 messagechannels 這兩個參數的協程可調用對象(callable):

  • message:一個ASGI消息(但有區別,見下文)
  • channels:一個字典( <unicode string> : <channel interface>

<channel interface> 是具有以下屬性的對象:

  • .send(message) 一個協程,用於發送返回的消息。可選
  • .receive() 一個協程,用於接收進來的消息。可選
  • .name 一個unicode字符串,channel的唯一標識。可選

uvicorn中的message區別於ASGI中的消息:

  • 消息還包括一個channel關鍵字,區別消息類型,例如:'channel':'http.request'
  • 消息不包括例如reply_channelbody_channel這樣的channel名稱,,而是channels字典可以查看允許的channel類型。

舉例:

傳進來的一個HTTP請求可能會是類似下面這樣的messagechannels.

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>
}

爲了做出響應,應用程序需要向replychannel發送(.send())一個http響應,例如:

await channels['reply'].send({
    'status': 200,
    'headers': [
        [b'content-type', b'text/plain'],
    ],
    'content': b'Hello, world'
})
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章