2011-10-13 12 views
13

Contesto: un'estensione per browser Chrome utilizza JQuery per richiedere una risposta da un'app django remota. Django riconosce che la richiesta viene effettuata tramite AJAX e risponde con "Ciao AJAX!". Sto basando il mio esercizio this great example. Poiché questa richiesta viene eseguita da un'estensione di Chrome, la richiesta viene eseguita su più siti, quindi ho utilizzato il decoratore @CSRF_exempt nella mia vista Django.Django dice is_ajax è falso su una richiesta JQuery AJAX

Problema: vista mio Django non riconosce la richiesta come una richiesta AJAX, e invece di rispondere Hello AJAX! risponde Hello not AJAX!. vista

mio Django:
(l'URL /xhr_test utilizza la seguente vista)

@csrf_exempt 
def check_login_extension(request): 
    if request.is_ajax(): 
     message = "Hello AJAX!" 
    else: 
     message = "Hello not AJAX" 
    return HttpResponse(message) 

La mia richiesta JQuery:

function xhrconnect() { 
    $.get("http://localhost:8000/xhr_test", function(data) { 
     document.getElementById('xhrmsg').innerHTML = (data); 
    }); 
} 
+0

Provare ad aggiungere una barra finale all'URL - 'http: // localhost: 8000/xhr_test /'. –

+0

Appena provato, ma nessun effetto. C'è qualcosa nel modo in cui JQuery invia richieste AJAX che richiedono una barra finale? So che '/ xhr_test' si sta risolvendo correttamente con la vista corretta, perché la vista sta rispondendo con il messaggio' Hello not AJAX'. Se JQuery non riuscisse a trovare l'URL corretto, non ci sarebbe alcun messaggio. – jchung

risposta

15

Passando attraverso la fonte jQuery, sembra che $.ajax() (e quindi $.get(), $.post(), ecc.) Sarà automaticamente imposta l'opzione crossDomain su true se rileva che stai effettuando una richiesta interdominio, che sei (relevant code here). E nella richiesta AJAX effettiva, jQuery non imposterà l'intestazione HTTP_X_REQUESTED_WITH di cui Django ha bisogno per is_ajax() se è impostato crossDomain (relevant code here).

Penso che il modo più semplice per risolvere questo problema è quello di impostare in modo esplicito crossDomain-false:

function xhrconnect() { 
    $.ajax({ 
     url: "http://localhost:8000/xhr_test", 
     success: function(data) { 
      document.getElementById('xhrmsg').innerHTML = (data); 
     }, 
     crossDomain: false 
    }); 
} 

Se questo non dovesse funzionare, si potrebbe provare a utilizzare un AJAX prefilter function per impostare manualmente la HTTP_X_REQUESTED_WITH intestazione in merito alla richiesta.

+0

Questa è una buona spiegazione del problema sottostante. Ho provato a impostare crossDomain su false, ma questo non risolve il problema. Suppongo che (a) la synax non sia corretta, o (b) il danno sia già stato fatto e l'impostazione di crossDomain su false dopo che il fatto non ha ripristinato l'intestazione 'HTTP_X_REQUESTED_WITH'. Eventuali altri potenziali problemi? Proverò la funzione di prefiltro AJAX ad un certo punto la prossima settimana e tornerò indietro. – jchung

+2

Non sono sicuro del motivo per cui non funziona, sembra impostare correttamente l'opzione, anche se non so come ispezionare le intestazioni delle richieste: http://jsfiddle.net/nrabinowitz/MYSDd/2/. Un'altra opzione sarebbe quella di passare in 'intestazioni: [{" X-Requested-With ":" XMLHttpRequest "}]' come opzione o in '$ .ajaxSetup()'. – nrabinowitz

+0

So che sono in ritardo per la festa, ma perché è considerato crossDomain se proviene dal suo dominio localhost al suo dominio localhost? – babonk

0

Si potrebbe anche voler dare un'occhiata a this page. Poiché Django offre una certa protezione contro le falsificazioni di richieste tra siti (CSRF), richiede alcune impostazioni speciali AJAX. Ho incluso l'installazione AJAX di seguito:

$(document).ajaxSend(function(event, xhr, settings) { 
    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; 
    } 
    function sameOrigin(url) { 
    // url could be relative or scheme relative or absolute 
    var host = document.location.host; // host + port 
    var protocol = document.location.protocol; 
    var sr_origin = '//' + host; 
    var origin = protocol + sr_origin; 
    // Allow absolute or scheme relative URLs to same origin 
    return (url == origin || url.slice(0, origin.length + 1) == origin + '/') || 
     (url == sr_origin || url.slice(0, sr_origin.length + 1) == sr_origin + '/') || 
     // or any other URL that isn't scheme relative or absolute i.e relative. 
     !(/^(\/\/|http:|https:).*/.test(url)); 
    } 
    function safeMethod(method) { 
    return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method)); 
    } 

    if (!safeMethod(settings.type) && sameOrigin(settings.url)) { 
    xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken')); 
    } 
}); 
+0

Si tratta ancora di un problema se l'OP utilizza un decoratore '@ csrf_exempt' sulla vista? – nrabinowitz

+0

Questo, non ne sono sicuro. Lo esaminerò, ma ricordo di avere problemi con le richieste di ajax finché non ho incluso il codice javascript sopra, e ho pensato che la risposta potesse essere preziosa. – NT3RP

+0

È un po 'complicato capire esattamente cosa sta succedendo in questo codice (colpa mia, non tua). Potresti spiegare come funziona questa configurazione w.r.t. La protezione CSRF di Django? – jchung