I'm working on a sign in form and am receiving the following message:
Method Not Allowed
The method is not allowed for the requested URL.
Reading a number of questions suggests that the URI of the flask handler should be the same as the one specified in the form's action attribute. I'm trying to submit the form's fields as part of a json object using the ajax API from jquery:
form.html
<form id="signin_form_id" onsubmit="sign_in()" method="post">
<label>Email: </label><input id="email0" type="email" name="l_email" required>
<br>
<label>Password: </label><input id="password0" type="password" name="l_password" required>
<br><br>
<input type="submit" value="Submit">
</form>
<!-- Body of the index page -->
<body>
<div class id="main"></div>
<script>
<!-- Display index page if session token not set -->
{% if page_body %}
if (localStorage.getItem("token") === null) {
document.getElementById("main").innerHTML = {{ page_body|safe }}
}
{% endif %}
</script>
</body>
the function sign_in() is defined as bellow:
client.js
function sign_in() {
var uri, method, formId, jsonObject;
uri = location.protocol + '//' + location.host + "/sign_in";
method = "POST";
formId = "#signin_form_id";
// Set-up ajax call
var request = {
url: uri,
type: method,
contentType: "application/json",
accepts: "application/json",
cache: false,
dataType: 'json',
data: JSON.stringify($(formId).serializeArray())
};
// Make the request
$.ajax(request).done(function(data) { // Handle the response
if(data.successSignIn === false) {
// Login failed; display index page
alert("Login failed!");
document.getElementById("main").innerHTML = document.getElementById("welcomeview").innerHTML;
} else {
// Login succeeded. We load the user's info, messages and also a form in which he can type messages
// Save the token received from the server. Could also be stored as a cookie
localStorage.setItem('token', data.token);
// Go to the home page
go_home();
}
}).fail(function(jqXHR) { // Handle failure
console.log("ajax error upon sign in " + jqXHR.status);
}
);
location.reload();
}
The server side code that handle's the request is:
serverside.py
@app.errorhandler(400)
def page_not_found(e):
# This page is returned if the request does not contain a json object
page_body = 'document.getElementById(\"welcomeview\").innerHTML;'
return render_template('client.html', page_body=page_body)
@app.route('/sign_in', methods=['POST'])
def sign_in_helper():
json_obj, code = decorator(sign_in, request, check_token=False)
# Check if the credentials are valid
if code == 401:
# Invalid login
page_body = 'document.getElementById(\"welcomeview\").innerHTML; alert(\"Invalid credentials!\")'
return render_template('client.html', page_body=page_body)
else:
# Return the token, the operation completion flag and the response code
return json_obj, code
def sign_in(email, password):
data = query_db('SELECT * FROM Users WHERE email = ?', [email], one=True)
if data and check_password_hash(data["password"], password):
token = token_creator()
insert_db('UPDATE Users SET token = ? WHERE email = ?', [token, email])
return jsonify(
successSignIn=True,
message="Welcome",
data=json.dumps({'token': token}),
), 200
return jsonify(
successSignIn=False,
message="Username or password invalid"), 401
def decorator(func, request, check_token):
data = request.get_json(force=True)
try:
if check_token:
token = data.get('token', None)
if token:
user = query_db('SELECT * FROM Users WHERE token = ?', [token], one=True)
if user:
json_obj, code = func(**data)
else:
json_obj = jsonify(success=False, message='Invalid token')
code = 401
else:
json_obj = jsonify(success=False, message='Misformatted data.')
code = 400
else:
json_obj, code = func(**data)
except (KeyError, TypeError, ValueError):
json_obj = jsonify(success=False, message='Misformatted data.')
code = 400
return json_obj, code
If I set the action attribute of the form to /sign_in the error is no longer sent, but then there are two submissions of the form data: one from the form and one in the AJAX call.
Why isn't the inner html set accordingly within the jquery call?