Python最快Web框架快速入門

關注頭條號,私信回覆資料會有意外驚喜呦………………最後一張照片有資料呦。

Python最快Web框架快速入門

Sanic 是一個和類Flask 的基於Python3.5+的web框架,它編寫的代碼速度特別快。

除了像Flask 以外,Sanic 還支持以異步請求的方式處理請求。這意味著你可以使用新的 async/await 語法,編寫非阻塞的快速的代碼。

關於 asyncio 包的介紹,請參考之前的一篇文章 python併發2:使用asyncio處理併發

Github 地址 是 https://github.com/channelcat/sanic,感興趣的可以去貢獻代碼。

既然它說速度特別快,我們先看下官方提供的 基準測試結果。

Sanic基準測試

Python最快Web框架快速入門

這個測試的程序運行在 AWS 實例上,系統是Ubuntu,只使用了一個進程。

Sanic 的開發者說他們的靈感來自於這篇文章 uvloop: Blazing fast Python networking。

那我們就有必要看下uvloop是個什麼庫。

uvloop

uvloop 是 asyncio 默認事件循環的替代品,實現的功能完整,切即插即用。uvloop是用CPython 寫的,建於libuv之上。

uvloop 可以使 asyncio 更快。事實上,它至少比 nodejs、gevent 和其他 Python 異步框架要快兩倍 。基於 uvloop 的 asyncio 的速度幾乎接近了 Go 程序的速度。

安裝 uvloop

uvloop 還只能在 *nix 平臺 和 Python3.5+以上版本使用。

使用pip安裝:

pip install uvloop

在 asyncio 代碼中使用uvloop 也很簡單:

import asyncio
import uvloop
asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())

這得代碼使得對任何asyncio.get_event_loop() 的調用都將返回一個uvloop實例。

詳細的uvloop 介紹可以看下原文:uvloop: Blazing fast Python networking。

uvloop的github地址是https://github.com/MagicStack/uvloop。

現在我們開始學習Sanic:

安裝 Sanic

pip install sanic

創建第一個 sanic 代碼

from sanic import Sanic
from sanic.response import text
app = Sanic(__name__)
@app.route("/")
async def test(request):
return text('Hello world!')
app.run(host="0.0.0.0", port=8000, debug=True)

運行代碼: python main.py, 現在打開瀏覽器訪問 http://0.0.0.0:8000,你會看到 hello world!。

如果你熟悉Flask,你會發現,這個語法簡直和Flask一模一樣。

Python最快Web框架快速入門

路由(Routing)

路由用於把一個函數綁定到一個 URL。下面是一些基本的例子:

@app.route('/')
def index():
return text('Index Page')
@app.route('/hello')
def hello():
return text('Hello World')

當然,你還可以動態的變化URL的某些部分,還可以為一個函數指定多個規則。

變量規則

通過把 URL 的一部分標記為就可以在 URL 中添加變量。標記的 部分會作為關鍵字參數傳遞給函數。通過使用,可以 選擇性的加上一個轉換器,為變量指定特定的類型,如果傳入的類型錯誤,Sanic會拋出NotFound異常。請看下面的例子:

from sanic.response import text
@app.route('/tag/')
async def tag_handler(request, tag):
return text('Tag - {}'.format(tag))
@app.route('/number/')
async def integer_handler(request, integer_arg):
return text('Integer - {}'.format(integer_arg))
@app.route('/number/')

async def number_handler(request, number_arg):
return text('Number - {}'.format(number_arg))
@app.route('/person/')
async def person_handler(request, name):
return text('Person - {}'.format(name))
@app.route('/folder/')
async def folder_handler(request, folder_id):
return text('Folder - {}'.format(folder_id))

HTTP 請求類型

默認情況下,我們定義的URL只支持GET 請求,@app.route裝飾器提供了一個可選參數methods,這個參數允許傳入所有HTTP 方法。

例如:

from sanic.response import text
@app.route('/post', methods=['POST'])
async def post_handler(request):
return text('POST request - {}'.format(request.json))
@app.route('/get', methods=['GET'])
async def get_handler(request):
return text('GET request - {}'.format(request.args))

也可以簡寫為:

from sanic.response import text
@app.post('/post')
async def post_handler(request):
return text('POST request - {}'.format(request.json))
@app.get('/get')
async def get_handler(request):
return text('GET request - {}'.format(request.args))

add_route 方法

除了@app.route裝飾器,Sanic 還提供了 add_route 方法。

@app.route 只是包裝了 add_route方法。

from sanic.response import text
# Define the handler functions
async def handler1(request):
return text('OK')
async def handler2(request, name):
return text('Folder - {}'.format(name))
async def person_handler2(request, name):
return text('Person - {}'.format(name))
# Add each handler function as a route
app.add_route(handler1, '/test')
app.add_route(handler2, '/folder/')
app.add_route(person_handler2, '/person/', methods=['GET'])

URL 構建

如果可以匹配URL,那麼Sanic可以生成URL嗎?當然可以,url_for() 函數就是用於構建指定函數的URL的。它把函數名稱作為第一個參數,其餘參數對應URL中的變量,例如:

@app.route('/')
async def index(request):
# generate a URL for the endpoint `post_handler`
url = app.url_for('post_handler', post_id=5)
# the URL is `/posts/5`, redirect to it
return redirect(url)
@app.route('/posts/')
async def post_handler(request, post_id):
return text('Post - {}'.format(post_id))

未定義變量會作為URL的查詢參數:

url = app.url_for('post_handler', post_id=5, arg_one='one', arg_two='two')
# /posts/5?arg_one=one&arg_two=two
# 支持多值參數
url = app.url_for('post_handler', post_id=5, arg_one=['one', 'two'])
# /posts/5?arg_one=one&arg_one=two

使用藍圖(Blueprint)

Sanic也提供了和Flask 類似的 Blueprint。

Blueprint有以下用途:

把一個應用分解為一套藍圖。這是針對大型應用的理想方案:一個項目可以實例化一個 應用,初始化多個擴展,並註冊許多藍圖。

在一個應用的 URL 前綴和(或)子域上註冊一個藍圖。 URL 前綴和(或)子域的參數 成為藍圖中所有視圖的通用視圖參數(缺省情況下)。

使用不同的 URL 規則在應用中多次註冊藍圖。

通過藍圖提供模板過濾器、靜態文件、模板和其他工具。藍圖不必執行應用或視圖 函數。

Python最快Web框架快速入門

blueprint 示例

from sanic import Sanic
from sanic.response import json
from sanic import Blueprint
bp = Blueprint('my_blueprint')
@bp.route('/')
async def bp_root(request):
return json({'my': 'blueprint'})
app = Sanic(__name__)
app.blueprint(bp)
app.run(host='0.0.0.0', port=8000, debug=True)

Sanic 使用 app.blueprint() 方法註冊blueprint。

使用藍圖註冊全局中間件

@bp.middleware
async def print_on_request(request):
print("I am a spy")
@bp.middleware('request')
async def halt_request(request):
return text('I halted the request')
@bp.middleware('response')
async def halt_response(request, response):
return text('I halted the response')
使用藍圖處理異常
@bp.exception(NotFound)
def ignore_404s(request, exception):
return text("Yep, I totally found the page: {}".format(request.url))

使用藍圖處理靜態文件

第一個參數指向當前的Python包

第二個參數是靜態文件的目錄

bp.static('/folder/to/serve', '/web/path')

使用url_for

如果要創建頁面鏈接,可以和通常一樣使用 url_for() 函數,只是要把藍圖名稱作為端點的前綴,並且用一個點( . )來 分隔:

@blueprint_v1.route('/')
async def root(request):
url = app.url_for('v1.post_handler', post_id=5) # --> '/v1/post/5'
return redirect(url)
@blueprint_v1.route('/post/')
async def post_handler(request, post_id):
return text('Post {} in Blueprint V1'.format(post_id))

操作請求數據

對於web 應用來說對客戶端向服務器發送的數據做出相應很重要,在Sanic中由傳入的參數 request來提供請求信息。

為什麼不像Flask 一樣提供一個全局變量 request?

Flask 是同步請求,每次請求都有一個獨立的新線程來處理,這個線程中也只處理這一個請求。而Sanic是基於協程的處理方式,一個線程可以同時處理幾個、幾十個甚至幾百個請求,把request作為全局變量顯然會比較難以處理。

Request 對象常用參數有

json(any) json body
from sanic.response import json
@app.route("/json")
def post_json(request):
return json({ "received": True, "message": request.json })

args(dict) URL請求參數

?key1=value1&key2=value2 將轉變為

{'key1': ['value1'], 'key2': ['value2']}

raw_args(dict) 和args 類似

?key1=value1&key2=value2 將轉變為

{'key1': 'value1', 'key2': 'value2'}

form(dict)處理 POST 表單請求,數據是一個字典

body(bytes)處理POST 表單請求,數據是一個字符串

其他參數還有:

  • file
  • ip
  • app
  • url
  • scheme
  • path
  • query_string

詳細信息參考文檔: Request Data

關於響應

Sanic使用response 函數創建響應對象。

  • 文本 response.text(‘hello world’)
  • html response.html(‘
  • hello world
  • ‘)
  • json response.json({‘hello’: ‘world’})
  • file response.file(‘/srv/www/hello.txt’)
  • streaming
from sanic import response
@app.route("/streaming")
async def index(request):
async def streaming_fn(response):
response.write('foo')
response.write('bar')
return response.stream(streaming_fn, content_type='text/plain')
  • redirect response.file(‘/json’)
  • raw response.raw(‘raw data’)
  • 如果想修改響應的headers可以傳入headers 參數
from sanic import response
@app.route('/json')
def handle_request(request):
return response.json(
{'message': 'Hello world!'},
headers={'X-Served-By': 'sanic'},
status=200
)

配置管理

應用總是需要一定的配置的。根據應用環境不同,會需要不同的配置。比如開關調試 模式、設置密鑰以及其他依賴於環境的東西。

Sanic 的設計思路是在應用開始時載入配置。你可以在代碼中直接硬編碼寫入配置,也可以使用配置文件。

不管你使用何種方式載入配置,都可以使用 Sanic 的 config 屬性來操作配置的值。 Sanic 本身就使用這個對象來保存 一些配置,擴展也可以使用這個對象保存配置。同時這也是你保存配置的地方。

Python最快Web框架快速入門

配置入門

config 實質上是一個字典的子類,可以像字典一樣操作:

app = Sanic('myapp')
app.config.DB_NAME = 'appdb'
app.config.DB_USER = 'appuser'
也可以一次更新多個配置:
db_settings = {
'DB_HOST': 'localhost',
'DB_NAME': 'appdb',
'DB_USER': 'appuser'
}
app.config.update(db_settings)

從對象導入配置

import myapp.default_settings
app = Sanic('myapp')
app.config.from_object(myapp.default_settings)

這裡是我寫的聊天機器人的真實配置示例:https://github.com/gusibi/momo/

使用配置文件

如果把配置放在一個單獨的文件中會更有用。理想情況下配置文件應當放在應用包的 外面。這樣可以在修改配置文件時不影響應用的打包與分發

常見用法如下:

app = Sanic('myapp')
app.config.from_envvar('MYAPP_SETTINGS')

首先從 myapp.default_settings 模塊載入配置,然後根據 MYAPP_SETTINGS 環境變量所指向的文件的內容重載配置的值。在 啟動服務器前,在 Linux 或 OS X 操作系統中,這個環境變量可以在終端中使用 export 命令來設置:

$ export MYAPP_SETTINGS=/path/to/config_file
$ python myapp.py

部署

Sanic 項目還不是特別成熟,現在部署比較簡陋。對Gunicorn的支持也不完善。

詳細信息可以 看下這個問題 Projects built with sanic?

先在說下我的部署方式

使用 supervisord 部署

supervisord 配置文件: https://github.com/gusibi/momo/blob/master/supervisord.conf

啟動 方式

supervisord -c supervisor.conf

總結

試用了下Sanic,把之前的一個聊天機器人從Flask 改成了 Sanic。不得不說,如果你有Flask經驗,大致看一下Sanic文檔就可以直接上手了。

並且Sanic 的速度比Flask 快很多,只是Sanic配套的包還是太少,用於生產環境有一定的風險。

很多人在問,學習Python讀什麼書,這其實是一個非常通用的問題,學習分為三種方式:看書、上課,而讀書學習是最實惠也是最高效的一種,小編整理了一些Python高分書籍給大家,從0基礎到高級適合不同學習階段,希望大家學習愉快。獲取方式:點擊小編頭像,關注後私信回覆“資料”即可下載。

Python最快Web框架快速入門


分享到:


相關文章: