【问题标题】:Flask view function losing request arguments when sending a POST request after GET request在 GET 请求后发送 POST 请求时,Flask 视图函数丢失请求参数
【发布时间】:2020-07-02 16:33:15
【问题描述】:

此视图在发出 GET 请求时接收 ?next= 参数,但一旦用户向同一视图发出 POST 请求,该参数就会丢失。我见过的示例没有明确传递查询参数,但似乎能够保留它们并在以下 POST 请求中获取它们。

@blueprint.route("/login", methods=["GET", "POST"])
@logout_required()
def login():
    form = LoginForm()
    #1
    print("NEXT:", request.args.get("next"))

    if form.validate_on_submit():
        u = User.query.filter_by(username=form.username.data).first()
        if u and u.check_password(password=form.password.data):
            if u.is_active():
                #2
                print("NEXT:", request.args.get("next"))

                login_user(u, remember=form.remember.data)

                next_url = request.args.get("next")
                if not next_url or url_parse(next_url).netloc != "":
                    next_url = url_for("main.index")

                return redirect(next_url)
            else:
                flash("This account has been disabled", "error")
        else:
            flash("Invalid password or username.", "error")

    return render_template("auth/login.html", form=form)

【问题讨论】:

  • 感谢您的链接。我已经设法缩小了来自我如何在<form> 中提交 POST 请求的问题。当我将<form> 操作属性设置为空字符串时,它会保留原始请求参数并将它们传递给视图函数。我不确定它以什么方式这样做,并且想知道是否有一种明确的方式来设置动作以传递参数。

标签: python http flask flask-login


【解决方案1】:

发现问题基本上是因为我将 GET 请求参数与 POST 输入提交混合在一起。

我的登录网址http://localhost:8000/auth/login?next=%2Fadmin

<form action="">

将向登录视图函数发送 POST 请求并允许通过request.args.get() 访问

但是,捕获和传递 GET 请求 next 参数的正确方法是通过一个隐藏的输入字段,该字段包含初始 GET 请求的 next 参数,允许它作为表单的一部分正确传递POST 请求。

<form action="{{ url_for('auth.login' }}">
    <input id="next" name="next" type="hidden" value="/admin">

视图函数:

@blueprint.route("/login", methods=["GET", "POST"])
@logout_required()
def login():
    form = LoginForm(next=request.args.get("next"))

【讨论】:

  • 作为参考,我在 Flask Mega Tutorial, part V 之后遇到了这个问题。没想到更改表单操作属性会导致 POST 请求如何传递 GET 请求参数的行为发生变化。
【解决方案2】:

在最后两个 flash() 函数之后,您缺少两个带有 return redirect() 的重定向,请参见下面的代码:

@blueprint.route("/login", methods=["GET", "POST"])
@logout_required()
def login():
    form = LoginForm()
    #1
    print("NEXT:", request.args.get("next"))

    if form.validate_on_submit():

        next_url = request.args.get("next")  #  -- HERE -- get "?next argument"

        u = User.query.filter_by(username=form.username.data).first()
        if u and u.check_password(password=form.password.data):
            if u.is_active():
                #2
                print("NEXT:", request.args.get("next"))

                login_user(u, remember=form.remember.data)

                # next_url = request.args.get("next")  # -- HERE -- 
                if not next_url or url_parse(next_url).netloc != "":
                    next_url = url_for("main.index")

                return redirect(next_url)

            else:
                flash("This account has been disabled", "error")
                return redirect(url_for('auth.index'))  # -- HERE --

        else:
            flash("Invalid password or username.", "error")
            return redirect(url_for('auth.login', next=next_url))  # -- HERE --

    return render_template("auth/login.html", form=form)

我假设/main 是受保护的路由并且当前没有会话,用户还没有登录,所以当用户尝试直接访问 p>

http://localhost:5000/admin

他将被自动重定向到这个urlauth.login 路由,带有参数?next=%2Fadmin%2F

http://localhost:5000/auth/login?next=%2Fadmin%2F

使用默认的flask-loginflash()消息Please log in to access this page.然后他可以登录,如果登录成功,他将登录并使用?next参数重定向到保护区,

但如果它发生并且诱惑失败了,我们有两个选择:

  • 如果Invalid password or username 他将被重定向auth.login 路由带有 ?next=%2Fadmin%2F 参数以获得第二次机会。

  • 但如果This account has been disabled 他将被重定向auth.login 路由没有 ?next=%2Fadmin%2F 参数,它确实有意义。

最后你不必担心?next= 的值,因为用户可以玩它甚至删除它和这个块

                if not next_url or url_parse(next_url).netloc != "":
                    next_url = url_for("main.index")

                return redirect(next_url)

默认为main.index(如果有)。

【讨论】:

  • 这不是我遇到的问题。那些闪烁通过并重新渲染模板,作为重定向到相同的视图函数。
  • flash() 不执行重定向,您需要明确添加它们,只需尝试代码然后查看。
  • 我知道flash() 不执行重定向。在这种情况下,我希望用户使用通过函数上的最终render_template() 实现的闪烁消息重新加载到同一个视图。您添加的第二个 redirect() 与现在发生的情况在行为上没有区别,而您添加的第一个 redirect() 不是我希望它们重定向的位置。
  • 我更新了我的答案,如果这正是你想要的,请告诉我。我用-- HERE --标记了更新的行
  • 您的第一个更改 next_url = request.args.get("next") # -- HERE -- get "?next argument" 是我最初遇到的问题,因为它在 POST 请求中丢失了。我已经提出了解决问题的方法。它还处理丢失 ?next 参数的问题,因为它保存在隐藏字段中。
猜你喜欢
  • 2018-12-14
  • 2020-08-28
  • 1970-01-01
  • 2015-07-25
  • 2016-10-17
  • 1970-01-01
  • 2017-05-22
  • 1970-01-01
  • 2018-07-05
相关资源
最近更新 更多