flask endpoint for ajax call - flask

I'm making an ajax call to my server while pressing submit button.
Button is present in page http://127.0.0.1:5000/post/15.
Jquery function invoked and the endpoint definition for submit_comment in python respectively:
function submit_comment(post_id) {
var uname = $('input[name="uname"]').val();
var comment = $('textarea[name="comment"]').val();
$.ajax({
url: "/submit_comment",
data: {name: uname, comment: comment, post_id: post_id},
method: "POST",
datatype: 'json',
success: function(response) {
console.log('reaches here');
addElement(response);
console.log('Is it me');
},
error: function(error) {
console.log('reached Error');
console.log(error);
}
});
}
py
#main.route('/submit_comment', methods = ['POST', 'PUT'])
def submit_comment():
entry = request.get_json(force=True)
print 'comment:', entry
....
Main is the blueprint. But I'm getting following 404 error.
127.0.0.1 - - [24/Aug/2017 10:30:55] "POST /post/submit_comment HTTP/1.1" 404 -
I am wondering from where this post got appended into the endpoint.
Can someone help me to understand the error and resolve it?
Thanks,
Deepak

I don't know a lot, but I know that the Flask docs on ajax say to query for the script root like this:
$SCRIPT_ROOT = {{ request.script_root|tojson }};
and then use that as part of the request URL.
An example from an ajax call I've used ($.getJSON being a jquery function for $.ajax)
$.getJSON($SCRIPT_ROOT + '{{ url_for("help_email") }}',

Related

Django - 403 (Forbidden): CSRF token missing or incorrect with Ajax call. Tried everything

I know this is a well worn question and I scoured the web and this website finding countless answers that boil down to the very same solutions and none of them worked for me and I do not know why. my info/trials so far:
suprisingly the csrf_exempt decorator does not work
tried setting up Headers/beforeSend once before all Ajax calls, it does not work (I tried setting the headers both in call and just once for all the ajax calls)
I can pick up the django token easily both via javascript or via django {{ token }}
django.middleware.csrf.CsrfViewMiddleware is present in the settings.py
python 3.8; django 2.2
[UPDATE] I tried removing contentType to no avail as well
here below you can see the different trials in /*...*/
var csrftoken = '{{ csrf_token }}'
$.ajaxSetup({
crossDomain: false,
beforeSend: function(xhr, settings) {
xhr.setRequestHeader("X-CSRFToken", csrftoken)
}
});
$.ajax({
url: '/do_things/',
type: 'POST',
contentType: 'application/json',
data: {
/*'csrfmiddlewaretoken': csrftoken*/
},
beforeSend: function (xhr) {
/*xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');*/
/*xhr.setRequestHeader('X-CSRFToken', csrftoken);*/
/*xhr.setRequestHeader('X-CSRF-Token', csrftoken);*/
},
headers: {
/*'X-CSRFToken': csrftoken,*/
/*'X-CSRF-Token': csrftoken*/
},
success: function (data) {
console.log('Fill all the tables')
}
})
on the view side
#login_required(login_url='/login/')
def do_things(request):
if request.method == "POST":
...
on the url side ( in case I messed up something here):
urlpatterns = [
#...
path('r/', views.do_things, name='do_things'),
]
Resources:
a) Forbidden (CSRF token missing or incorrect.) | Django and AJAX
b) Adding CSRFToken to Ajax request
c) https://docs.djangoproject.com/en/2.2/ref/csrf/
let csrftoken = '{{ csrf_token }}'
$.ajax({
type: "POST",
headers:{'X-CSRFToken':csrftoken},
url: "{% url 'Wishlist' %}",
data: {'product_id':product_id},
success: function (response) {
console.log(response, typeof(response))
}
})
I used simple ajax with csrf in the header and it's working fine.
when i use your code in mine, so function calls but data gets blank. i have refered this Django csrf token for Ajax

Latest Chrome caching ajax response despite no cache headers

I have a simple form in a modal that gets populated by a ajax request (to a server running Django)
If I add choices to a choice field, those choices are not displaying for a few minutes on the modal. This issues only appeared after updating to the latest version of chrome (80.3987.149).
I am including no-cache headers in the ajax response like this:
response['Cache-Control'] = 'no-cache, no-store, must-revalidate'
response['Pragma'] = 'no-cache'
response['Expires'] = '0'
But it doesn't seem to matter.
My ajax call method looks like this:
openAlertModalOnclick(e) {
e.preventDefault();
let self = this;
$.get($(e.target).attr("href"), resp => {
$("#alertModal").html(resp.html).foundation("open").foundation();
})
}).fail(() => {
this.showErrorToast("Error occurred while loading alerts.")
})
}
I am 90% sure this is an issue with just the latest version of chrome, as I could not reproduce it until I updated chrome. Is there anything else I can do to get chrome to stop caching the form?
The solution was the change the $.get call to $.ajax and pass in a cache: false parameter.
The function to open the modal now looks like this:
openForm52AlertModalOnclick(e) {
e.preventDefault();
let self = this;
SpinnerController.showSpinner();
$.ajax({
url: $(e.target).attr("href"),
method: 'GET',
cache: false,
success: function (resp) {
$("#alertModal").html(resp.html).foundation("open").foundation();
},
error: function () {
this.showErrorToast("Error occurred while loading alerts.")
},
});

csrf error while trying to delete an object with ajax

I have all the objects from my db rendered on my template by an ajax function.
Near every object there's a button that should delete it from the db but since I'm working on Django it raise a csrf_token missing or incorrect error.
I'm not using a form so I don't know how to include the csrf_token.
var $orders = $('#orders')
$.ajax({
type: 'GET',
url: 'http://127.0.0.1:8000/MyApp/list-api/?format=json',
success: function(orders) {
$.each(orders, function(i, order){
$orders.append('<li>name: '+order.name+', drink:
'+order.drink+'</li>')
$orders.append("<button data-id=" +(order.pk)+"
class='remove'>X</button>")
});
},
error: function() {
alert('errore caricamento ordini');
}
});
$orders.delegate('.remove', 'click', function(){
$.ajax({
type: 'DELETE',
url: 'http://127.0.0.1:8000/MyApp/list-api/' +
$(this).attr('data-id')
});
});
When I press a remove button a new request appears in the network panel of the browser, the response states :detail: "CSRF Failed: CSRF token missing or incorrect." The console gives a 403 forbidden error.
Any help or hints are really appreciated.

Ajax post for django form not working

For some reason I cannot get a successful post when trying to use ajax. The code I am trying is here:
http://jsfiddle.net/MRKNq/11/
$('#register_form').submit(function(e) {
$.ajax({
type: "POST",
url: "/echo/json/",
data: $('#register_form').serialize(),
success: function(data) {
alert(data.text);
$('#result').text(data.text);
},
type: 'POST'
});
e.preventDefault();
});​
Any suggestions would be greatly appreciated.
You should look at the response that comes back in Firebug or some other tool. This likely has to do with CSRF.
Have a look at this: https://docs.djangoproject.com/en/dev/ref/contrib/csrf/#ajax
You can also exempt your view from CSRF protection by using this decorator: https://docs.djangoproject.com/en/dev/ref/contrib/csrf/#django.views.decorators.csrf.csrf_exempt

"CSRF token missing or incorrect" while post parameter via AJAX in Django

I try to post parameter like
jQuery.ajax(
{
'type': 'POST',
'url': url,
'contentType': 'application/json',
'data': "{content:'xxx'}",
'dataType': 'json',
'success': rateReviewResult
}
);
However, Django return Forbidden 403. CSRF verification failed. Request aborted.
I am using 'django.middleware.csrf.CsrfViewMiddleware' and couldn't find how I can prevent this problem without compromising security.
You can make AJAX post request in two different ways:
To tell your view not to check the csrf token. This can be done by using decorator #csrf_exempt, like this:
from django.views.decorators.csrf import csrf_exempt
#csrf_exempt
def your_view_name(request):
...
To embed a csrf token in each AJAX request, for jQuery it may be:
$(function () {
$.ajaxSetup({
headers: { "X-CSRFToken": getCookie("csrftoken") }
});
});
Where the getCookie function retrieves csrf token from cookies. I use the following implementation:
function getCookie(c_name)
{
if (document.cookie.length > 0)
{
c_start = document.cookie.indexOf(c_name + "=");
if (c_start != -1)
{
c_start = c_start + c_name.length + 1;
c_end = document.cookie.indexOf(";", c_start);
if (c_end == -1) c_end = document.cookie.length;
return unescape(document.cookie.substring(c_start,c_end));
}
}
return "";
}
Also, jQuery has a plugin for accessing cookies, something like that:
// set cookie
$.cookie('cookiename', 'cookievalue');
// read cookie
var myCookie = $.cookie('cookiename');
// delete cookie
$.cookie('cookiename', null);
The simplest way I have found is to include the {{csrf_token}} value in the data:
jQuery.ajax(
{
'type': 'POST',
'url': url,
'contentType': 'application/json',
'data': {
'content': 'xxx',
'csrfmiddlewaretoken': '{{ csrf_token }}',
},
'dataType': 'json',
'success': rateReviewResult
}
);
It took me a while to understand what to do with the code that Daniel posted. But actually all you have to do is paste it at the beginning of the javascript file.
For me, the best solution so far is:
Create a csrf.js file
Paste the code in the csrf.js file
Reference the code in the template you need it
<script type="text/javascript" src="{{ STATIC_PREFIX }}js/csrf.js"></script>
Notice that STATIC_PREFIX/js/csrf.js points to my file. I am actually loading the STATIC_PREFIX variable with {% get_static_prefix as STATIC_PREFIX %}.
Advanced tip: if you are using templates and have something like base.html where you extend from, then you can just reference the script from there and you don't have to worry anymore in there rest of your files. As far as I understand, this shouldn't represent any security issue either.
Simple and short
$.ajaxSetup({
headers: { "X-CSRFToken": '{{csrf_token}}' }
});
OR
function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
$.ajaxSetup({
beforeSend: function(xhr, settings) {
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", '{{csrf_token}}');
}
}
});
docs
For lack of a straight forward answer, you just have to add the header X-CSRFToken to the ajax request which is in the cookie csrftoken. JQuery doesn't do cookies (for some reason) without a plugin so:
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-cookie/1.4.1/jquery.cookie.min.js"></script>
and the minimal code change is:
$.ajax({
headers: { "X-CSRFToken": $.cookie("csrftoken") },
...
});
The fastest solution without any plugins if you are not embedding js into your template is:
Put <script type="text/javascript"> window.CSRF_TOKEN = "{{ csrf_token }}"; </script> before your reference to script.js file in your template, then add csrfmiddlewaretoken into your data dictionary:
$.ajax({
type: 'POST',
url: somepathname + "do_it/",
data: {csrfmiddlewaretoken: window.CSRF_TOKEN},
success: function() {
console.log("Success!");
}
})
If you do embed your js into the template, it's as simple as: data: {csrfmiddlewaretoken: '{{ csrf_token }}'}
I got the same issue yesterday and thought it would help people if there were a simple way to handle it, so I wrote a jQuery plugin for that: jquery.djangocsrf. Instead of adding the CSRF token in every request, it hooks itself on the AjaxSend jQuery event and adds the client cookie in a header.
Here’s how to use it:
1- include it:
<script src="path/to/jquery.js"></script>
<script src="path/to/jquery.cookie.js"></script>
<script src="path/to/jquery.djangocsrf.js"></script>
2- enable it in your code:
$.djangocsrf( "enable" );
Django always add the token in a cookie if your template uses {% csrf_token %}. To ensure it always adds it even if you don’t use the special tag in your template, use the #ensure_csrf_cookie decorator:
from django.views.decorators.csrf import ensure_csrf_cookie
#ensure_csrf_cookie
def my_view(request):
return render(request, 'mytemplate.html')
Note: I’m using Django 1.6.2.
Thank you everyone for all the answers. I am using Django 1.5.1. I'm a little late to the party, but here goes.
I found the link to the Django project to be very useful, but I didn't really want to have to include the extra JavaScript code every time I wanted to make an Ajax call.
I like jerrykan's response as it is very succinct and only adds one line to an otherwise normal Ajax call. In response to the comments below his comment regarding situations when Django template tags are unavailable, how about loading up the csrfmiddlewaretoken from the DOM?
var token = $('input[name="csrfmiddlewaretoken"]').prop('value');
jQuery.ajax({
type: 'POST',
url: url,
data: { 'csrfmiddlewaretoken': token },
dataType: 'json',
success: function(data) { console.log('Yippee! ' + data); }
});
EDIT March 2016
My approach to this issue over the past few years has changed. I add the code below (from the Django docs) to a main.js file and load it on every page. Once done, you shouldn't need to worry about the CSRF token with ajax again.
function getCookie(name) {
var cookieValue = null;
if (document.cookie && document.cookie != '') {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = jQuery.trim(cookies[i]);
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) == (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
var csrftoken = getCookie('csrftoken');
Include x-csrftoken header in request:
var token = $('input[name="csrfmiddlewaretoken"]').prop('value');
jQuery.ajax({
type: 'POST',
url: url,
beforeSend : function(jqXHR, settings) {
jqXHR.setRequestHeader("x-csrftoken", get_the_csrf_token_from_cookie());
},
data: data,
dataType: 'json',
});
If, after reading other answers, someone is still struggling please try this:
$.ajax({
type: "POST",
beforeSend: function (request)
{
request.setRequestHeader("X-CSRF-TOKEN", "${_csrf.token}");
},
url: servlet_path,
data : data,
success : function(result) {
console.log("Success!");
}
});
Please not that when doing it this way make sure you don't have the {% csrf_token %} inside the <form></form> tags. Then as explained here add the following code to your javascript
function getCookie(name) {
let cookieValue = null;
if (document.cookie && document.cookie !== '') {
const cookies = document.cookie.split(';');
for (let i = 0; i < cookies.length; i++) {
const cookie = cookies[i].trim();
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
const csrftoken = getCookie('csrftoken');
// using js fetch
// https://docs.djangoproject.com/en/3.1/ref/csrf/#setting-the-token-on-the-ajax-request
const request = new Request(
/* URL */,
{headers: {'X-CSRFToken': csrftoken}}
);
fetch(request, {
method: 'POST',
mode: 'same-origin' // Do not send CSRF token to another domain.
}).then(function(response) {
// ...
});
Just want to put it out here that if GET works in your use case, then it wouldn't need the CSRF token. For my use case, using GET was OK.
html
<form action="">
{% csrf_token %}
</form>
JS
<script>
const csrftoken = document.querySelector('[name=csrfmiddlewaretoken]').value;
const request = new Request(
'url_here',
{headers: {'X-CSRFToken': csrftoken}}
);
fetch(request, {
method: 'POST',
// mode: 'same-origin' optinal // Do not send CSRF token to another domain.
}).then(function(response) {
console.log(response);
});
</script>
reference link for more detail
As a summary for my mistakes:
Don't forget to set the request content type.
Get the csrf value, either from
The template {{ csrf_token }}
The cookie, use the snippet in django site
NB. The default cookie name is csrftoken, but can be overriden by CSRF_COOKIE_NAME setting.
The DOM, if you can't access the cookie (you set CSRF_USE_SESSIONS or CSRF_COOKIE_HTTPONLY to True)
document.querySelector('[name=csrfmiddlewaretoken]').value;
Set the request header, I'am using XMLHttpRequest
const Http = new XMLHttpRequest();
Http.setRequestHeader("X-CSRFToken", CSRF_VALUE);
Http.setRequestHeader("X_CSRFTOKEN", CSRF_VALUE);
The header name is managed by CSRF_HEADER_NAME setting, which its default is HTTP_X_CSRFTOKEN.
But: "The header name received from the server is normalized by converting all characters to uppercase, replacing any hyphens with underscores, and adding an 'HTTP_' prefix to the name" src.
So, If you set the HTTP_X_CSRFTOKEN header, Django will convert it to HTTP_HTTP_X_CSRFTOKEN which wis incorrect name and will raise CSRF missed error.
Http.setRequestHeader("X-CSRFToken", csrftoken); // This worked
Http.setRequestHeader("X-CSRFTOKEN", csrftoken); // Also this
Http.setRequestHeader("HTTP-X-CSRFToken", csrftoken); // Not working
Http.setRequestHeader("HTTP_X_CSRFTOKEN", csrftoken); // Not Working
Http.setRequestHeader("X_CSRFTOKEN", csrftoken); // Not working !!
Don't use url in ajax that is different than that of the browser 127.0.0.1 & localhost are not the same !!
No need to set data.append("csrfmiddlewaretoken", csrftoken); in the request body, As I know.