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)
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)
...
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.
Related
Here is a code snippet that is a simple note application that takes in input from the user and displays the notes on the browser. The notes are stored in the session variable provided by flask. My question is that even though the server is running and the notes I entered are in the variable, why does the notes variable clear when I close the browser?
How can I make it persist even after the browser closes? Please let me know a solution with the use of session variable only.
from flask import Flask, render_template, request, session
from flask_session import Session
app = Flask(__name__)
app.config["SESSION_PERMANENT"] = False
app.config["SESSION_TYPE"] = "filesystem"
Session(app)
print(app.config)
notes = []
#app.route("/", methods=["GET", "POST"])
def index():
if session.get("notes") is None:
session["notes"]=[]
if request.method == "POST":
note = request.form.get("note")
session["notes"].append(note)
return render_template("index.html", notes=session["notes"])
Session ID's are generated and stored as a client cookie when the user starts communicating with the server. The sessions themselves are stored in the server (usually in memory, but this is implementation based).
Sessions are meant to be based on single user interaction with a web page. If you don't set a (sufficiently) long expiry for the cookie, it'll wipe the cookie when the browser is exited. Try setting a SET-COOKIE field on the HTTP response timeout.
I'm trying to store JWT Tokens in cookies for a Flask application to restrict some endpoints. An endpoint, "/authorize" , is responsible for setting the cookies then redirect the page to the root endpoint, "/".
from flask import Flask, request, make_response, redirect
#app.route("/authorize", methods=["GET"])
def authorize():
token = request.args.get('token')
expires = request.args.get('expires')
# some code to validate the token
resp_output = make_response(redirect("/"))
resp_output.set_cookie("token", token, expires=expires)
return resp_output
#app.route("/", methods=["GET"])
def index():
token = request.cookies.get("token)
# do something with the token
However, when I tried to deploy this, I ran into some problems with the redirecting and therefore have to change redirect("/") to redirect("https://someaddress.com/)" where https://someaddress.com/ is the address of the flask application. Now when I try to retrieve the token cookies in the root endpoint, it returns None. I suspect it is because the redirection has turnt from an internal one to an external one.
Please help me find a workaround for this. Or if you think I should resolve the problems that lead to the change from internal to external redirection so I can go back to what works. (If anyone can point me to some resources explaining exactly how redirection, or more specifically Flask's redirection, works, I'd really appreciate it.)
Using url_for function from flask should work in your case, as it will look for the link within the app context:
from flask import Flask, request, make_response, redirect, url_for
#app.route("/authorize", methods=["GET"])
def authorize():
token = request.args.get('token')
expires = request.args.get('expires')
# some code to validate the token
resp_output = make_response(redirect(url_for('index')))
resp_output.set_cookie("token", token, expires=expires)
return resp_output
#app.route("/", methods=["GET"])
def index():
token = request.cookies.get("token)
# do something with the token
Btw, I would recommend you pass your authorization logic to a decorator, have a look on authorization decorators using flask.
In case this don't work in production, that can be some setting related to your reverse proxy - like nginx conf file. Let me know if it is the case
on Nginx file on sites-enabled folder etc/nginx/sites-enabled/<project-name>, comment or remove the following line:
proxy_set_header Host $host;
Hope it suits you well!
I checked every SO question about it, but the answers are mainly on import errors while I do not have such a problem. Mainly I followed this article followed by this one to have a functioning registration.
Instead of using Flask-SQLalchemy I wanted to create my own database (for fun), but when I try to access the database (DButils.py) functions it occurs an internal server error.
The flask code at the top is:
from flask import Flask, render_template, flash, redirect, url_for, session,
from wtforms import Form, StringField, TextAreaField, PasswordField, validators
from functools import wraps
from DButils import *
My folder follows the same order of the git, with DButils.py in the same folder as app.py.
I did not encounter the error when I import the module, but only when I try to call its functions. In DButils.py I have only a signup function:
def signup(nick, email, password):
return True
And when I try to call it in the app.py code like:
#app.route('/register', methods=['GET', 'POST'])
def register():
form = RegisterForm(request.form)
if request.method == 'POST' and form.validate():
email = form.email.data
nick = form.nick.data
password = form.password.data
signup(nick,email,password) #WHEN COMMENTED NO ERROR OCCURS
return redirect(url_for('login'))
return render_template('register.html', form=form)
I get the message "Internal Server Error" with no other clue about it. What can it be? How can I call a function in an external module in Flask?
Thanks for your help!
I found the answer by an trial-error approach. Apparently using pkill --signal SIGHUP uwsgi in combination with sudo systemctl restart nginx.
I am trying to run a very simple flask-application on a (shared) WSGI server. The code works fine when I run it with the build-in server, but if I try to POST to the URL on the production WSGI server, I receive a 404, The requested URL was not found on the server error.
This only occurs for POST requests, GET and PUT are processed as expected.
By removing the placeholder tid, flask can be convinced to properly process the request, but this is obviously not a proper solution.
The server is running Phusion Passenger, the flask version is 1.0.2.
As it is a shared server, I have no further access to the server configuration.
What can cause flask to seemingly forget routes on a WSGI-server?
A minimal example that reproduces to behaviour (on the server only, of course) can be seen below:
from flask import Flask
from flask.views import MethodView
app = Flask(__name__)
class API(MethodView):
def get(self, tid=0):
return "Test"
def put(self, tid=0):
return "Test"
def post(self, tid=0):
return "Test"
app.add_url_rule("/test/<int:tid>", view_func=API.as_view('api'))
You have to specify the methods you use in add_url_rule:
app.add_url_rule("/test/<int:tid>", view_func=API.as_view('api'), methods=['GET', 'PUT', 'POST'])
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)
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)
...
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.