上一节我们学习了基本的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.con 原创,没有猿人学授权,请勿以任何形式转载。***
说点什么吧...