Sebastian Karlsson
Sebastian Karlsson

Reputation: 745

Flask hangs when sending a post request to itself

I'm trying to send a post request to my Flask app from one of its own views, but it hangs until I kill the server. If I do the request in JavaScript, it works fine. Why does it not work from the Python code?

from flask import Blueprint, render_template, abort, request, Response, session, url_for
from jinja2 import TemplateNotFound

from flask.ext.wtf import Form
from wtforms import BooleanField, TextField, PasswordField

import requests

login = Blueprint('login', __name__, template_folder='templates')

class LoginForm(Form):
    email = TextField('Email')
    password = PasswordField('Password')

@login.route('/login', methods=['GET', 'POST'])
def _login():

    form = LoginForm(request.form, csrf_enabled=False)

    if form.validate_on_submit():
        return requests.post(request.url_root + '/api/login', data={"test": True})
    
    return render_template('login.html', form=form)

Upvotes: 18

Views: 11224

Answers (2)

davidism
davidism

Reputation: 127410

Prior to 1.0, Flask's development server was single-threaded by default. In that mode, it can only handle one request at a time. Making a request blocks until it receives the response. Your Flask code makes a request in the one thread, and then waits. There are no other threads to handle this second request. So the request never completes, and the original request waits forever.

Enable threads in the dev server to avoid the deadlock and fix the immediate problem.

app.run(threaded=True)

However, making a full HTTP request to the app from within the app should never be necessary and indicates a deeper design issue. For example, observe that the internal request will not have access to the session on the client's browser. Extract the common code and call it internally, rather than making a new request.

def common_login(data):
    ...

@app.route("/login")
def login():
    ...
    common_login(data)
    ...

@app.route("/api/login")
def api_login():
    ...
    common_login(data)
    ...

Upvotes: 31

John Gordon
John Gordon

Reputation: 33359

I'm not familiar with Flask. However this bit of code:

if form.validate_on_submit():
    return requests.post(request.url_root + '/api/login', data={"test": True})

Seems like you're accepting a posted form, validating it, and then posting it again. Over and over.

Upvotes: 0

Related Questions