vrs vrs - 4 months ago 44
Ajax Question

POST request through AJAX results in error 404 in Firefox only

In my Flask-app I try to implement POST request through AJAX call when user clicks on the link.
It works like a charm in Chromium. I have no problems when requesting my view function through

httpie
either:

$ http --json POST http://127.0.0.1:5000/ctrl/remove-category id=1 csrf=1

(venv) $ : http --json POST http://127.0.0.1:5000/ctrl/remove-category id=5 csrf=1
HTTP/1.0 200 OK
Content-Length: 78
Content-Type: application/json
Date: Sat, 09 Jul 2016 09:05:20 GMT
Server: Werkzeug/0.11.8 Python/3.5.1

{
"message": "Category 'test 5' has been removed",
"status": "success"
}


But in Firefox something strange happens. I tested it under two FF profiles. Both of them give me 404 error. When clicking the link under my first FF profile I get 404 and nothing happens, i.e. I don't even see POST request to Werkzeug server, only GET request.

Under the second FF profile I still get an error in Firebug console:

POST http://127.0.0.1:5000/ctrl/remove-category 31ms jquery.min.js (line 6)
Error code: 404 categories (line 455)


So POST request is sent and I see it in my Werkzeug logs:

127.0.0.1 - - [09/Jul/2016 11:29:11] "POST /ctrl/remove-category HTTP/1.1" 200 -
127.0.0.1 - - [09/Jul/2016 11:29:12] "GET /ctrl/categories HTTP/1.1" 200 -


Nonetheless, I still don't get other things done in my AJAX `.success' call (like saving things to localStorage, etc.)

Here is my jQuery script:

<script>
$('.remove').click( function() {
var data = {};
data['csrf'] = $('#csrf-removal').val()
data['id'] = $(this).data('id-removal');

$.ajaxSetup({
beforeSend: function(xhr, settings) {
if (!/^(GET|HEAD|OPTIONS|TRACE)$/i.test(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", data['csrf'])
}
}
});

var remove = confirm('Are you sure?');
if (remove == true) {
$.ajax({
url: "{{ url_for('ctrl.remove_category', _external=True) }}",
type: 'post',
dataType: 'json',
contentType: 'application/json;charset=UTF-8',
data: JSON.stringify(data, null, '\t'),
success: function(response) {
// message to user
var flash = "<div class='alert alert-" + response['status'] + "'>" +
"<button type='button' class='close' data-dismiss='alert'>&times;</button>" +
response['message'] + "</div>";
// save message to localStorage
window.onbeforeunload = function() {
localStorage.setItem('message', flash);
}
// reload the page
location.reload();
// jump to the top of the page
$('html,body').scrollTop(0);
},
error: function(jqXHR, textStatus, errorThrown) {
console.log('Error code: ' + jqXHR.status);
}
});
}
});
</script>


This is my view function:

@csrf.exempt # for httpie testing
@ctrl.route('/remove-category', methods=['POST'])
#@permission_required(Permission.ADMINISTER) # httpie testing
def remove_category():
try:
id = request.json['id']
csrf = request.json['csrf']
except KeyError:
return jsonify({
'status': 'error',
'message': 'Function takes two parameters: '
'id of the entry to be removed; csrf token',
})

category = Category.query.get_or_404(id)
if category.posts.count():
status = 'warning'
message = "Category '{0}' is not empty and cannot be removed".\
format(category.title)
else:
status = 'success'
message = "Category '{0}' has been removed".\
format(category.title)
db.session.delete(category)
return jsonify({
'status': status,
'message': message,
})


I'm using jQuery 2.0.3, Flask 0.10.1, Flask-WTF 0.9.4 and Firefox 47.0.
I'm very new to javascript and cross-browser things related to js, so any help is appreciated.

P.S. I'm aware of this topic, but using
accepts
with 'application/json' in ajax call didn't help.

UPDATE: Using DevTools in Chromium and Firebug in Firefox, I copied POST requests from both browsers as cURL commands and compared their results:


  1. Chromium (see gist) works as expected, server gets a request and sends response.

  2. Firefox (see gist) doesn't work. Request sent, but response is never received.
    cURL' is hanging untill I terminate it with
    ^C'. Upon termination I see logs that
    Werkzeug
    webserver returns error 400:

    127.0.0.1 - - [09/Jul/2016 14:29:01] "POST /ctrl/remove-category HTTP/1.1" 400


vrs vrs
Answer

Okay, I've found the problem.

After reading this bug report, I upgraded to jQuery 2.1.1. That resulted in getting error code 0 instead of 404. Status code 0 could mean that my script reloads the page before it gets AJAX response (see this SO topic).

So I added setTimeout for 1 sec delay before reloading the page:

setTimeout(function() { // wait 1 sec
    location.reload();  // reload page
    $('html,body').scrollTop(0); // jump on top
}, 1000); 

And that did the trick.

P.S. setTimeout is a temporary workaround to see if it solves the problem. The right way to do things like that is using promises (see jQuery.when/done)

Comments