Flask 重定向到上一个页面

在项目中我们会遇到一些应用场景,在访问某个URL后重定向到上一个页面。比如我们在访问一个博客页面时,点击评论链接就直接重定向到登录页面,当用户登录后合理的行为是跳转到评论页面而不是主页面。如下示例:

def func_a():
    return "<h2>这是a页面</h2><a href='{}'>do_something</a>".format(url_for('do_something'))


@app.route('/b')
def func_b():
    return "<h2>这是b页面</h2><a href='{}'>do_something</a>".format(url_for('do_something'))


@app.route('/do-something')
def do_something():
    print('do things.....')
    return redirect(url_for('test'))

这里我们访问完这个视图后直接调到固定的test页面中,但是我们希望重定向到原来的页面:

1.获取上个页面的url

(1)HTTP.referrer
是一个用来记录请求发源地址的,即访问来源。
所以do_something可以返回:

 return redirect(request.referrer)

但是referrer字段在很多情况下是空值,所以为了保险返回固定页面:

 return redirect(request.referrer or url_for('test'))

(2)查询参数
在URL中手动加入包含当前页面url的查询参数,这个参数一般命名为next。

@app.route('/a')
def func_a():
    return "<h2>这是a页面</h2><a href='{}'>do_something</a>".format(url_for('do_something', next=request.full_path))


@app.route('/b')
def func_b():
    return "<h2>这是b页面</h2><a href='{}'>do_something</a>".format(url_for('do_something', next=request.full_path))

这里的request.full_path获取的是当前页面的完整路径,在do_something视图中获取next值,重定向到指定路径:

return redirect(request.args.get('next'))

为避免next为空,可以如下:

return redirect(request.args.get('next'),url_for('test'))

为了更全面的考虑,可以将两者结合,将两者封装到函数中,如下:

def redirect_back(default='test', **kwargs):
    for target in request.args.get('next'), request.referrer:
        if target:
            return redirect(target)
    return redirect(url_for(default, **kwargs))

此方法同时兼顾了多种情况。
相应的do_something视图中的返回改为:

@app.route('/do-something')
def do_something():
    print('do things.....')
    return redirect_back()

2.对URL进行安全验证

在重定向的过程中url的安全问题值得考虑,如next的值为一个跳向钓鱼网的链接,那后果不堪设想。
为了确保URL安全,就要对next的值进行验证:

def is_safe_url(url):
    ref_url = urlparse(request.host_url)
    test_url = urlparse(urljoin(request.host_url, url))
    return test_url.scheme in ('http', 'https') and ref_url.netloc == test_url.netloc

此方法将next的url作为参数,并通过request.host_url获取程序内的主机URL,然后使用urljoin()函数将url转成绝对url。接着用urlparse()函数解析两个url,最后对目标url的url模式和主机地址进行验证,确保只有程序内的url才能被返回。
通过此方法验证redirect_back()中的next值和referrer:

def redirect_back(default='test', **kwargs):
    for target in request.args.get('next'), request.referrer:
        if not target:
            continue
        print(is_safe_url(target))
        if is_safe_url(target):
            return redirect(target)
    return redirect(url_for(default, **kwargs))

完成跳转的上个页面。

参考资料:《Flask Web 开发实战》

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章