Python Web框架Sanic 路由进阶

发表时间:2020-02-18

上一节我们学习了基本的Sanic 路由知识,本节我们深入Sanic路由,这包括: url_for 方法,WebSocket路由,用户定义的路由名称和为静态文件(Sanic static)建立URL。

Sanic route路由进阶

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'

文章来源互联网,如有侵权,请联系管理员删除。邮箱:417803890@qq.com / QQ:417803890

微配音

Python Free

邮箱:417803890@qq.com
QQ:417803890

皖ICP备19001818号-4
© 2019 copyright www.pythonf.cn - All rights reserved

微信扫一扫关注公众号:

联系方式

Python Free