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 開發實戰》

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