Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Flask hangs when sending a post request to itself

Tags:

python

flask

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)
like image 387
Sebastian Karlsson Avatar asked Oct 26 '15 18:10

Sebastian Karlsson


1 Answers

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)
    ...
like image 96
davidism Avatar answered Sep 17 '22 15:09

davidism