上一節我們學習了基本的Sanic 路由知識,本節我們深入Sanic路由,這包括:url_for
方法,WebSocket路由,使用者定義的路由名稱和為靜態檔案(Sanic static)建立URL。
用url_for
方法建立URL
Sanic提供了一個url_for
方法,來基於處理函式名生成URL。它可以用於避免在程式碼中硬編碼url路徑,取而代之的是僅僅用處理函式名。比如:
from sanic.response import redirect
@app.route('/')
async def index(request):
# 引用處理函式名稱`user_handler`生成一個URL
url = app.url_for('user_handler', user_id=5)
# 生成的url是:`/users/5`, redirect to it
return redirect(url)
@app.route('/users/<user_id>')
async def user_handler(request, user_id):
return text('User - {}'.format(user_id))
使用url_for
需要注意:
(1)傳遞給url_for
的關鍵詞引數如果不是請求引數就會被加入到URL的查詢字串(query string),例如:
url = app.url_for('user_handler', user_id=5, arg_one='one', arg_two='two')
# /users/5?arg_one=one&arg_two=two
(2)多值引數可以傳遞給url_for
,比如:
url = app.url_for('user_handler', user_id=5, arg_one=['one', 'two'])
# /users/5?arg_one=one&arg_one=two
(3)有些特殊引數(_anchor
, _external
, _scheme
, _server
)傳遞給url_for
會建立特殊的url(其中,_method
目前尚未支援)。例如:
url = app.url_for('user_handler', user_id=5, arg_one='one', _anchor='anchor')
# /users/5?arg_one=one#anchor
url = app.url_for('user_handler', user_id=5, arg_one='one', _external=True)
# //server/users/5?arg_one=one
# _external requires you to pass an argument _server or set SERVER_NAME in app.config if not url will be same as no _external
url = app.url_for('user_handler', user_id=5, arg_one='one', _scheme='http', _external=True)
# http://server/users/5?arg_one=one
# when specifying _scheme, _external must be True
# you can pass all special arguments at once
url = app.url_for('user_handler', user_id=5, arg_one=['one', 'two'], arg_two=2, _anchor='anchor', _scheme='http', _external=True, _server='another_server:8888')
# http://another_server:8888/users/5?arg_one=one&arg_one=two&arg_two=2#anchor
(4)所有有效的請求引數必須傳遞給url_for
來建立URL。如果有一個請求引數沒有提供,或者一個引數的型別不匹配,就會產生URLBuildError
異常。
Websocket 路由
Websocket協議的路由可以透過@app.websocket
裝飾器定義:
@app.websocket('/feed')
async def feed(request, ws):
while True:
data = 'hello!'
print('Sending: ' + data)
await ws.send(data)
data = await ws.recv()
print('Received: ' + data)
另外,app.add_websocket_route
方法可以取代裝飾器:
async def feed(request, ws):
pass
app.add_websocket_route(my_websocket_handler, '/feed')
WebSocket路由的處理函式別呼叫時,第一個引數是request(跟http路由一樣),第二個引數是WebSocket協議物件,它有send
和recv
兩個方法分別用以傳送和接收資料。
strict_slashes
引數
我們可以決定路由是否嚴格匹配末尾的斜槓,透過引數strict_slashes
進行設定:
# 設定整個app所有路由的預設strict_slashes值
app = Sanic('strict_slash', strict_slashes=True)
# 可以為個別路由重新設定strict_slashes 值
# 因為strict_slashes=False,訪問路徑`/get`和`/get/`都可以得到`OK`
@app.get('/get', strict_slashes=False)
def handler(request):
return text('OK')
# 該引數同樣適用於blueprints
bp = Blueprint('bp_strict_slash', strict_slashes=True)
@bp.get('/bp/get', strict_slashes=False)
def handler(request):
return text('OK')
app.blueprint(bp)
當strict_slashes=True
時,路由設定的路徑必須和訪問的URL路徑完全一致才行,也就是路由設定的路徑以斜槓/
結尾則訪問的URL也必須以斜槓/
結尾;
當strict_slashes=False
時,訪問URL後面可加可不加斜槓/
,比如上例中訪問路徑/get
和/get/
都可以得到OK
。
使用者定義的路由名稱
透過傳遞引數name
給路由裝飾器就可以自定義路由名稱,該引數會覆蓋預設使用hanler.__name__
屬性的路由名稱。這個路由名稱是給url_for
使用的。
app = Sanic('test_named_route')
@app.get('/get', name='get_handler')
def handler(request):
return text('OK')
# 當為上面的路由使用`url_for`時,
# 應該使用 `app.url_for('get_handler')`
# 而不是`app.url_for('handler')`
# 同樣適用於blueprints
bp = Blueprint('test_named_bp')
@bp.get('/bp/get', name='get_handler')
def handler(request):
return text('OK')
app.blueprint(bp)
# 應該使用 `app.url_for('test_named_bp.get_handler')`
# 而不是 `app.url_for('test_named_bp.handler')`
# 同一個url的不同方法可以使用不同的名字,但是對應`url_for`來說,它們都是對應同一個url:
@app.get('/test', name='route_test')
def handler(request):
return text('OK')
@app.post('/test', name='route_post')
def handler2(request):
return text('OK POST')
@app.put('/test', name='route_put')
def handler3(request):
return text('OK PUT')
# 下面生成的url都相同,可以使用它們中的任何一個:
# '/test'
app.url_for('route_test')
# app.url_for('route_post')
# app.url_for('route_put')
# 同一個處理函式名對應不同方法時,
# 就需要知道`name` (為了`url_for`)
@app.get('/get')
def handler(request):
return text('OK')
@app.post('/post', name='post_handler')
def handler(request):
return text('OK')
# 因此:
# app.url_for('handler') == '/get'
# app.url_for('post_handler') == '/post'
為靜態檔案建立URL
Sanic 支援使用url_for
方法建立靜態檔案url。如果靜態url指向一個資料夾,url_for
方法的filename
引數可以忽略。
app = Sanic('test_static')
app.static('/static', './static')
app.static('/uploads', './uploads', name='uploads')
app.static('/the_best.png', '/home/ubuntu/test.png', name='best_png')
bp = Blueprint('bp', url_prefix='bp')
bp.static('/static', './static')
bp.static('/uploads', './uploads', name='uploads')
bp.static('/the_best.png', '/home/ubuntu/test.png', name='best_png')
app.blueprint(bp)
# then build the url
app.url_for('static', filename='file.txt') == '/static/file.txt'
app.url_for('static', name='static', filename='file.txt') == '/static/file.txt'
app.url_for('static', name='uploads', filename='file.txt') == '/uploads/file.txt'
app.url_for('static', name='best_png') == '/the_best.png'
# blueprint url building
app.url_for('static', name='bp.static', filename='file.txt') == '/bp/static/file.txt'
app.url_for('static', name='bp.uploads', filename='file.txt') == '/bp/uploads/file.txt'
app.url_for('static', name='bp.best_png') == '/bp/static/the_best.png'
我的公眾號:猿人學 Python 上會分享更多心得體會,敬請關注。
***版權申明:若沒有特殊說明,文章皆是猿人學 yuanrenxue.com 原創,沒有猿人學授權,請勿以任何形式轉載。***