--- title: Usare XMLHttpRequest slug: Web/API/XMLHttpRequest/Using_XMLHttpRequest translation_of: Web/API/XMLHttpRequest/Using_XMLHttpRequest original_slug: Web/API/XMLHttpRequest/Usare_XMLHttpRequest ---
Per inviare una richiesta HTTP, crea un oggetto {{domxref("XMLHttpRequest")}}, apri un URL, ed invia la richiesta. Dopo che la transazione è completata, l'oggetto conterrà informazioni utili come il testo di risposta e lo stato HTTP. Questa pagina illustra alcuni dei più comuni e oscuri casi d'uso di questo potente oggetto XMLHttpRequest
.
function reqListener () { console.log(this.responseText); } var oReq = new XMLHttpRequest(); oReq.onload = reqListener; oReq.open("GET", "http://www.example.org/example.txt"); oReq.send();
Una richiesta inviata con XMLHttpRequest può essere restituita in due modi, sincrona o asincrona. Il tipo di richiesta viene deciso dall'argomento opzionale async
(il terzo argomento) che viene impostato nel metodo open() di {{domxref("XMLHttpRequest.open()")}}. Se l'argomento è true
o se non è specificato, il XMLHttpRequest
è processato in maniera asincrona, in caso contrario è processato in maniera sincrona. Una discussione dettagliata è una dimostrazione di queste due tipologie di richieste possono essere trovate nella pagina richieste sincrone ed asincrone. In generale, dovresti usare raramente le richieste sincrone, se mai ne farai uso.
Ci sono vari tipi di attributi di risposta definite dallo standard W3C sul costruttore XMLHttpRequest. Questi sono in grado di fornire al client che effettua la richiesta importanti informazioni sullo stato della risposta. In alcuni casi in cui si lavora con risposte di tipo non testuale possono riguardare alcuni elementi di analisi e manipulazioni come evidenziato dai paragrafi seguenti.
responseXML
Se si usa l'oggetto XMLHttpRequest
per ricevere il contenuto di un documento XML remoto, la proprietà responseXML
dell'oggetto stesso sarà assegnata a un oggetto DOM contentente un il documento XML a cui è stata effettuata una operazione di parsing. Se si lavora con tale proprietà può essere difficile analizzare e modificare tale proprietà. Di seguito sono riportate i quattro principali metodi per lavorare con tale documento XML:
responseText
contenentente un documento HTMLXMLHttpRequest.responseXML
. SI legga l'articolo a riguardo HTML in XMLHttpRequest per dettagli.Se si utilizza l'oggetto XMLHttpRequest
per ottenere il contenuto di una pagina HTML remota, la proprietà responseText
conterrà un amalgama di tutti i tag HTML. Ciò può essere difficile da manipolare e analizzare. Ci sono principalmente tre divere metodologie per analizzare questo insieme:
XMLHttpRequest.responseXML
.fragment.body.innerHTML
e navigare il codice DOM del fragment.Nonostante l'oggetto XMLHttpRequest
è principalmente utilizzato per ricevere e inviare dati testuali, può essere utilizzato per inviare e ricevere dati dal contenuto binario. Esistono svariati metodi ben testati per fare sì che l'oggetto in questione invii dati binari. Questi metodo prevedono l'utilizzo del metodo .overrideMimeType(...)
sull'oggetto.
var oReq = new XMLHttpRequest(); oReq.open("GET", url, true); // riceve dei dati non porcessati come una stringa binaria oReq.overrideMimeType("text/plain; charset=x-user-defined"); /* ... */
La XMLHttpRequest Level 2 Specification aggiunge un nuovo attributo responseType che permette di inviare e ricevere dati binari in modo molto più semplice.
var oReq = new XMLHttpRequest(); oReq.open("GET", url, true); oReq.responseType = "arraybuffer"; oReq.onload = function(e) { var arraybuffer = oReq.response; // non responseText /* ... */ } oReq.send();
Per più esempi si veda la pagina Sending and Receiving Binary Data.
L'oggetto XMLHttpRequest
fornisce la possibilità di ascoltare svariati eventi che possono occorrere mentre la richiesta è processata. Questo inclulde periodici aggiornamenti sul progresso, notificazione di errori e così via.
Il supporto agli eventi di monitoraggio del progresso DOM dell'oggetto XMLHttpRequest
ripetta le API specification progress events: tali eventi implementano l'interfaccia {{domxref("ProgressEvent")}}.
var oReq = new XMLHttpRequest(); oReq.addEventListener("progress", updateProgress, false); oReq.addEventListener("load", transferComplete, false); oReq.addEventListener("error", transferFailed, false); oReq.addEventListener("abort", transferCanceled, false); oReq.open(); // ... // progress on transfers from the server to the client (downloads) function updateProgress (oEvent) { if (oEvent.lengthComputable) { var percentComplete = oEvent.loaded / oEvent.total; // ... } else { // Impossibile elaborare il progresso perche' non si conosce la grandezza totale } } function transferComplete(evt) { alert("Trasferimento completato!"); } function transferFailed(evt) { alert("E' avvenuto un errore nel trasferimento"); } function transferCanceled(evt) { alert("Il trasferimento è stato cancellato dall'utente"); }
Le linee 3-6 aggiungono degli event listener per i vari eventi che sono inviati mentre si performa un trasferimento di dati con l'oggetto XMLHttpRequest
.
open()
sulla richiesta. Se ciò non viene effettuato gli eventi non vengono inviati.L'event handler per il progresso, specificato dalla funzione updateProgress()
in questo esempio, riceve il numero totale di byte da trasferire e il numero di byte trasferiti finora nei campi total
e loaded
rispettivamente. In ogni caso, se il campo lengthComputable
risulta falsa, la lunghezza totale risulta sconosciuta e sarà riportata come zero.
Gli eventi di progresso esistono sia per il download che per l'upload. Gli eventi di download sono notificati sull'oggetto XMLHttpRequest
stesso, come indicato dall'esempio sopra. Quelli di upload, invece, sono notificati sull'attributo XMLHttpRequest.upload
come mostrato sotto:
var oReq = new XMLHttpRequest(); oReq.upload.addEventListener("progress", updateProgress, false); oReq.upload.addEventListener("load", transferComplete, false); oReq.upload.addEventListener("error", transferFailed, false); oReq.upload.addEventListener("abort", transferCanceled, false); oReq.open();
file://
.Nota: A partire da {{Gecko("9.0")}}, gli eventi di progresso possono essere lanciati per ogni parte di dato ricevuta, inclusa l'ultima parte dove l'ultimo pacchetto è ricevuto e la connesione chiusa prima che l'evento di progresso sia notificato. In questo caso l'evento di progresso è notificato automaticamente quando occorre l'evento di "load" per tale pacchetto. Questo permette di creare un monitoraggio affidabile solamente osservando gli eventi di progresso.
Nota: A partire da {{Gecko("12.0")}}, se l'evento di progresso è chiamato con un responseType
di tipo moz-blob
, il valore di risposta sarà un {{domxref("Blob")}} contenente i dati ricevuti fino a quel punto.
Si puà anche rilevare tutti e tre le tipologie di terminazione del caricamento(abort
, load
o error
) utilizzando l'evento loadend
:
req.addEventListener("loadend", loadEnd, false); function loadEnd(e) { alert("Trasferimento terminato (anche se non sappiamo come)."); }
Si noti che non c'è modo di essere sicuri di conoscere con le informazioni ricevute dall'evento loadend
quali condizioni hanno causato il termine dell'operazione. In ogni caso si può usare questo per gestire operazioni che devono essere eseguite al termine del trasferimento.
Istanze di un oggetto XMLHttpRequest
possono essere usate per inviare form in principalmente due modi:
FormData
Il secondo modo (utilizzando l'oggetto FormData
) è il più semplice e veloce, ma ha lo svantaggio che i dati raccolto non possono essere trasformati in stringa.
Il primo modo, invece, è più complesso, ma è anche in cambio più potente e flessibile.
XMLHttpRequest
Inviare form senza le API dell'oggetto FormData
non richiede l'utilizzo di altre API tranne nel caso di FileReader
nel caso si voglia caricare più di un file.
Un html {{ HTMLElement("form") }} può essere inviata in quattro possibili modi:
POST
e assegnando all'attributo enctype
il valore application/x-www-form-urlencoded
(default);POST
e assegnando all'attributo enctype
il valore text/plain
;POST
e assegnando all'attributo enctype
il valore multipart/form-data
;GET
(in tal caso l'attributo enctype
sarà ignorato).Ora, si consideri di inviare una form contenente solo due campi, chiamati foo
e baz
. Se si sta utilizzando il metodo POST
il server riceverà una stringa simile a una delle seguenti tre linee a seconda del tipo di encoding utilizzato:
Metodo: POST
; Encoding type: application/x-www-form-urlencoded
(default):
Content-Type: application/x-www-form-urlencoded foo=bar&baz=The+first+line.%0D%0AThe+second+line.%0D%0A
Metodo: POST
; Encoding type: text/plain
:
Content-Type: text/plain foo=bar baz=The first line. The second line.
Metodo: POST
; Encoding type: multipart/form-data
:
Content-Type: multipart/form-data; boundary=---------------------------314911788813839 -----------------------------314911788813839 Content-Disposition: form-data; name="foo" bar -----------------------------314911788813839 Content-Disposition: form-data; name="baz" The first line. The second line. -----------------------------314911788813839--
Invece, se si utilizza un metodo GET
una stringa simile alla seguente sarà semplicemente aggiunta all'URL:
?foo=bar&baz=The%20first%20line.%0AThe%20second%20line.
Tutte queste cose sono eseguite automaticamente dal web browser ogni volta che si esegue il submit di una {{ HTMLElement("form") }}. Ma se si vuole fare lo stesso usando JavaScript bisogna istruire l'interprete su tutte le operazioni da eseguire. Inviare delle form in AJAX puro risulta troppo complesso per essere spiegato qui; per questa ragione abbiamo creato un framework completo (ma comunque puramente didattico) che possa essere usato in tutti e quattro i metodi di submit e anche per caricare dei file.
<!doctype html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <title>Sending forms with pure AJAX – MDN</title> <script type="text/javascript"> "use strict"; /*\ |*| |*| :: XMLHttpRequest.prototype.sendAsBinary() Polyfill :: |*| |*| https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest#sendAsBinary() \*/ if (!XMLHttpRequest.prototype.sendAsBinary) { XMLHttpRequest.prototype.sendAsBinary = function(sData) { var nBytes = sData.length, ui8Data = new Uint8Array(nBytes); for (var nIdx = 0; nIdx < nBytes; nIdx++) { ui8Data[nIdx] = sData.charCodeAt(nIdx) & 0xff; } /* send as ArrayBufferView...: */ this.send(ui8Data); /* ...or as ArrayBuffer (legacy)...: this.send(ui8Data.buffer); */ }; } /*\ |*| |*| :: AJAX Form Submit Framework :: |*| |*| https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest/Using_XMLHttpRequest |*| |*| This framework is released under the GNU Public License, version 3 or later. |*| http://www.gnu.org/licenses/gpl-3.0-standalone.html |*| |*| Syntax: |*| |*| AJAXSubmit(HTMLFormElement); \*/ var AJAXSubmit = (function () { function ajaxSuccess () { /* console.log("AJAXSubmit - Success!"); */ alert(this.responseText); /* you can get the serialized data through the "submittedData" custom property: */ /* alert(JSON.stringify(this.submittedData)); */ } function submitData (oData) { /* the AJAX request... */ var oAjaxReq = new XMLHttpRequest(); oAjaxReq.submittedData = oData; oAjaxReq.onload = ajaxSuccess; if (oData.technique === 0) { /* method is GET */ oAjaxReq.open("get", oData.receiver.replace(/(?:\?.*)?$/, oData.segments.length > 0 ? "?" + oData.segments.join("&") : ""), true); oAjaxReq.send(null); } else { /* method is POST */ oAjaxReq.open("post", oData.receiver, true); if (oData.technique === 3) { /* enctype is multipart/form-data */ var sBoundary = "---------------------------" + Date.now().toString(16); oAjaxReq.setRequestHeader("Content-Type", "multipart\/form-data; boundary=" + sBoundary); oAjaxReq.sendAsBinary("--" + sBoundary + "\r\n" + oData.segments.join("--" + sBoundary + "\r\n") + "--" + sBoundary + "--\r\n"); } else { /* enctype is application/x-www-form-urlencoded or text/plain */ oAjaxReq.setRequestHeader("Content-Type", oData.contentType); oAjaxReq.send(oData.segments.join(oData.technique === 2 ? "\r\n" : "&")); } } } function processStatus (oData) { if (oData.status > 0) { return; } /* the form is now totally serialized! do something before sending it to the server... */ /* doSomething(oData); */ /* console.log("AJAXSubmit - The form is now serialized. Submitting..."); */ submitData (oData); } function pushSegment (oFREvt) { this.owner.segments[this.segmentIdx] += oFREvt.target.result + "\r\n"; this.owner.status--; processStatus(this.owner); } function plainEscape (sText) { /* how should I treat a text/plain form encoding? what characters are not allowed? this is what I suppose...: */ /* "4\3\7 - Einstein said E=mc2" ----> "4\\3\\7\ -\ Einstein\ said\ E\=mc2" */ return sText.replace(/[\s\=\\]/g, "\\$&"); } function SubmitRequest (oTarget) { var nFile, sFieldType, oField, oSegmReq, oFile, bIsPost = oTarget.method.toLowerCase() === "post"; /* console.log("AJAXSubmit - Serializing form..."); */ this.contentType = bIsPost && oTarget.enctype ? oTarget.enctype : "application\/x-www-form-urlencoded"; this.technique = bIsPost ? this.contentType === "multipart\/form-data" ? 3 : this.contentType === "text\/plain" ? 2 : 1 : 0; this.receiver = oTarget.action; this.status = 0; this.segments = []; var fFilter = this.technique === 2 ? plainEscape : escape; for (var nItem = 0; nItem < oTarget.elements.length; nItem++) { oField = oTarget.elements[nItem]; if (!oField.hasAttribute("name")) { continue; } sFieldType = oField.nodeName.toUpperCase() === "INPUT" ? oField.getAttribute("type").toUpperCase() : "TEXT"; if (sFieldType === "FILE" && oField.files.length > 0) { if (this.technique === 3) { /* enctype is multipart/form-data */ for (nFile = 0; nFile < oField.files.length; nFile++) { oFile = oField.files[nFile]; oSegmReq = new FileReader(); /* (custom properties:) */ oSegmReq.segmentIdx = this.segments.length; oSegmReq.owner = this; /* (end of custom properties) */ oSegmReq.onload = pushSegment; this.segments.push("Content-Disposition: form-data; name=\"" + oField.name + "\"; filename=\""+ oFile.name + "\"\r\nContent-Type: " + oFile.type + "\r\n\r\n"); this.status++; oSegmReq.readAsBinaryString(oFile); } } else { /* enctype is application/x-www-form-urlencoded or text/plain or method is GET: files will not be sent! */ for (nFile = 0; nFile < oField.files.length; this.segments.push(fFilter(oField.name) + "=" + fFilter(oField.files[nFile++].name))); } } else if ((sFieldType !== "RADIO" && sFieldType !== "CHECKBOX") || oField.checked) { /* field type is not FILE or is FILE but is empty */ this.segments.push( this.technique === 3 ? /* enctype is multipart/form-data */ "Content-Disposition: form-data; name=\"" + oField.name + "\"\r\n\r\n" + oField.value + "\r\n" : /* enctype is application/x-www-form-urlencoded or text/plain or method is GET */ fFilter(oField.name) + "=" + fFilter(oField.value) ); } } processStatus(this); } return function (oFormElement) { if (!oFormElement.action) { return; } new SubmitRequest(oFormElement); }; })(); </script> </head> <body> <h1>Sending forms with pure AJAX</h1> <h2>Using the GET method</h2> <form action="register.php" method="get" onsubmit="AJAXSubmit(this); return false;"> <fieldset> <legend>Registration example</legend> <p> First name: <input type="text" name="firstname" /><br /> Last name: <input type="text" name="lastname" /> </p> <p> <input type="submit" value="Submit" /> </p> </fieldset> </form> <h2>Using the POST method</h2> <h3>Enctype: application/x-www-form-urlencoded (default)</h3> <form action="register.php" method="post" onsubmit="AJAXSubmit(this); return false;"> <fieldset> <legend>Registration example</legend> <p> First name: <input type="text" name="firstname" /><br /> Last name: <input type="text" name="lastname" /> </p> <p> <input type="submit" value="Submit" /> </p> </fieldset> </form> <h3>Enctype: text/plain</h3> <form action="register.php" method="post" enctype="text/plain" onsubmit="AJAXSubmit(this); return false;"> <fieldset> <legend>Registration example</legend> <p> Your name: <input type="text" name="user" /> </p> <p> Your message:<br /> <textarea name="message" cols="40" rows="8"></textarea> </p> <p> <input type="submit" value="Submit" /> </p> </fieldset> </form> <h3>Enctype: multipart/form-data</h3> <form action="register.php" method="post" enctype="multipart/form-data" onsubmit="AJAXSubmit(this); return false;"> <fieldset> <legend>Upload example</legend> <p> First name: <input type="text" name="firstname" /><br /> Last name: <input type="text" name="lastname" /><br /> Sex: <input id="sex_male" type="radio" name="sex" value="male" /> <label for="sex_male">Male</label> <input id="sex_female" type="radio" name="sex" value="female" /> <label for="sex_female">Female</label><br /> Password: <input type="password" name="secret" /><br /> What do you prefer: <select name="image_type"> <option>Books</option> <option>Cinema</option> <option>TV</option> </select> </p> <p> Post your photos: <input type="file" multiple name="photos[]"> </p> <p> <input id="vehicle_bike" type="checkbox" name="vehicle[]" value="Bike" /> <label for="vehicle_bike">I have a bike</label><br /> <input id="vehicle_car" type="checkbox" name="vehicle[]" value="Car" /> <label for="vehicle_car">I have a car</label> </p> <p> Describe yourself:<br /> <textarea name="description" cols="50" rows="8"></textarea> </p> <p> <input type="submit" value="Submit" /> </p> </fieldset> </form> </body> </html>
Per testarlo, create una pagina chiamata register.php (al quale fanno riferimento gli attributi action di queste form) e inserite il seguente contenuto.
<?php /* register.php */ header("Content-type: text/plain"); /* NOTE: You should never use `print_r()` in production scripts, or otherwise output client-submitted data without sanitizing it first. Failing to sanitize can lead to cross-site scripting vulnerabilities. */ echo ":: data received via GET ::\n\n"; print_r($_GET); echo "\n\n:: Data received via POST ::\n\n"; print_r($_POST); echo "\n\n:: Data received as \"raw\" (text/plain encoding) ::\n\n"; if (isset($HTTP_RAW_POST_DATA)) { echo $HTTP_RAW_POST_DATA; } echo "\n\n:: Files received ::\n\n"; print_r($_FILES);
La sintassi per attivare lo script è semplicemente:
AJAXSubmit(myForm);
FileReader
per eseguire l'upload dei file. QUesta è una API recente e non ancora implementata nei browser come IE9 o inferiori. Per questa ragione l'upload AJAX-only è considerato una tecnica sperimentale. Se non si ha bisogno dell'upload di file binari questo framework funzionera egregiamente nella maggior parte dei browser.send()
e possibilmente il metodo readAsArrayBuffer()
dell'API FileReader
. Ma, siccome l'obiettivo di questo script è di fuonzionare con dei dati stringifiabli, si è usato il metodo sendAsBinary()
assieme al metodo readAsBinaryString()
delle API FileReader
. Per questo, lo script sopra funziona sono quando si stanno gestendo file di piccole dimensioni. Se non si intende caricare del contenuto binario, considerare anche l'utilizzo delle API FormData
.Il costruttore FormData
permette di compliare una serie di coppie chiave/valore da inviare utilizzando una XMLHttpRequest
. Si utilizza principalmente per inviare dati in una form, ma può essere usato indipendentemente dalle form per inviare dei dati con chiavi. I dati trasmessi sono gli stessi del formato utilizzato dal metodo submit()
che le form usano per inviare i dati se il tipo encoding indicato è "multipart/form-data". Gli oggetti FormData possono essere utilizzati in uno svariato numero possibile con una XMLHttpRequest. Per esempi o speigazioni di come utilizzare una FormData con XMLHttpRequest si veda la pagina Usare l'oggetto FormData. Per fini didattici di seguito una traduzione dell'esempio precedente modificato per accettare l'API delle FormData
. Si noti la brevità del codice.
<!doctype html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <title>Sending forms with FormData – MDN</title> <script type="text/javascript"> "use strict"; function ajaxSuccess () { alert(this.responseText); } function AJAXSubmit (oFormElement) { if (!oFormElement.action) { return; } var oReq = new XMLHttpRequest(); oReq.onload = ajaxSuccess; if (oFormElement.method.toLowerCase() === "post") { oReq.open("post", oFormElement.action, true); oReq.send(new FormData(oFormElement)); } else { var oField, sFieldType, nFile, sSearch = ""; for (var nItem = 0; nItem < oFormElement.elements.length; nItem++) { oField = oFormElement.elements[nItem]; if (!oField.hasAttribute("name")) { continue; } sFieldType = oField.nodeName.toUpperCase() === "INPUT" ? oField.getAttribute("type").toUpperCase() : "TEXT"; if (sFieldType === "FILE") { for (nFile = 0; nFile < oField.files.length; sSearch += "&" + escape(oField.name) + "=" + escape(oField.files[nFile++].name)); } else if ((sFieldType !== "RADIO" && sFieldType !== "CHECKBOX") || oField.checked) { sSearch += "&" + escape(oField.name) + "=" + escape(oField.value); } } oReq.open("get", oFormElement.action.replace(/(?:\?.*)?$/, sSearch.replace(/^&/, "?")), true); oReq.send(null); } } </script> </head> <body> <h1>Sending forms with FormData</h1> <h2>Using the GET method</h2> <form action="register.php" method="get" onsubmit="AJAXSubmit(this); return false;"> <fieldset> <legend>Registration example</legend> <p> First name: <input type="text" name="firstname" /><br /> Last name: <input type="text" name="lastname" /> </p> <p> <input type="submit" value="Submit" /> </p> </fieldset> </form> <h2>Using the POST method</h2> <h3>Enctype: application/x-www-form-urlencoded (default)</h3> <form action="register.php" method="post" onsubmit="AJAXSubmit(this); return false;"> <fieldset> <legend>Registration example</legend> <p> First name: <input type="text" name="firstname" /><br /> Last name: <input type="text" name="lastname" /> </p> <p> <input type="submit" value="Submit" /> </p> </fieldset> </form> <h3>Enctype: text/plain</h3> <p>The text/plain encoding is not supported by the FormData API.</p> <h3>Enctype: multipart/form-data</h3> <form action="register.php" method="post" enctype="multipart/form-data" onsubmit="AJAXSubmit(this); return false;"> <fieldset> <legend>Upload example</legend> <p> First name: <input type="text" name="firstname" /><br /> Last name: <input type="text" name="lastname" /><br /> Sex: <input id="sex_male" type="radio" name="sex" value="male" /> <label for="sex_male">Male</label> <input id="sex_female" type="radio" name="sex" value="female" /> <label for="sex_female">Female</label><br /> Password: <input type="password" name="secret" /><br /> What do you prefer: <select name="image_type"> <option>Books</option> <option>Cinema</option> <option>TV</option> </select> </p> <p> Post your photos: <input type="file" multiple name="photos[]"> </p> <p> <input id="vehicle_bike" type="checkbox" name="vehicle[]" value="Bike" /> <label for="vehicle_bike">I have a bike</label><br /> <input id="vehicle_car" type="checkbox" name="vehicle[]" value="Car" /> <label for="vehicle_car">I have a car</label> </p> <p> Describe yourself:<br /> <textarea name="description" cols="50" rows="8"></textarea> </p> <p> <input type="submit" value="Submit" /> </p> </fieldset> </form> </body> </html>
file
nel campo {{ HTMLElement("input") }}, quando si invia una form attraverso l'API FormData
API non è necessario utilizzare le API FileReader
: i file sono automaticamente caricati.function getHeaderTime () { alert(this.getResponseHeader("Last-Modified")); /* A valid GMTString date or null */ } var oReq = new XMLHttpRequest(); oReq.open("HEAD" /* use HEAD if you only need the headers! */, "yourpage.html", true); oReq.onload = getHeaderTime; oReq.send();
Let's create these two functions:
function getHeaderTime () { var nLastVisit = parseFloat(window.localStorage.getItem('lm_' + this.filepath)), nLastModif = Date.parse(this.getResponseHeader("Last-Modified")); if (isNaN(nLastVisit) || nLastModif > nLastVisit) { window.localStorage.setItem('lm_' + this.filepath, Date.now()); isFinite(nLastVisit) && this.callback(nLastModif, nLastVisit); } } function ifHasChanged(sURL, fCallback) { var oReq = new XMLHttpRequest(); oReq.open("HEAD" /* use HEAD - we only need the headers! */, sURL, true); oReq.callback = fCallback; oReq.filepath = sURL; oReq.onload = getHeaderTime; oReq.send(); }
Test:
/* Let's test the file "yourpage.html"... */ ifHasChanged("yourpage.html", function (nModif, nVisit) { alert("The page '" + this.filepath + "' has been changed on " + (new Date(nModif)).toLocaleString() + "!"); });
If you want to know whether the current page has changed, please read the article about document.lastModified
.
Modern browsers support cross-site requests by implementing the web applications working group's Access Control for Cross-Site Requests standard. As long as the server is configured to allow requests from your web application's origin, XMLHttpRequest
will work. Otherwise, an INVALID_ACCESS_ERR
exception is thrown.
A, cross-browser compatible approach to bypassing the cache is to append a timestamp to the URL, being sure to include a "?" or "&" as appropriate. For example:
http://foo.com/bar.html -> http://foo.com/bar.html?12345 http://foo.com/bar.html?foobar=baz -> http://foo.com/bar.html?foobar=baz&12345
Since the local cache is indexed by URL, this causes every request to be unique, thereby bypassing the cache.
You can automatically adjust URLs using the following code:
var oReq = new XMLHttpRequest(); oReq.open("GET", url + ((/\?/).test(url) ? "&" : "?") + (new Date()).getTime(), true); oReq.send(null);
{{fx_minversion_note(3, "Versions of Firefox prior to Firefox 3 allowed you to set the preference capability.policy.<policyname>.XMLHttpRequest.open</policyname>
to allAccess
to give specific sites cross-site access. This is no longer supported.")}}
{{fx_minversion_note(5, "Versions of Firefox prior to Firefox 5 could use netscape.security.PrivilegeManager.enablePrivilege(\"UniversalBrowserRead\");
to request cross-site access. This is no longer supported, even though it produces no warning and permission dialog is still presented.")}}
The recommended way to enable cross-site scripting is to use the Access-Control-Allow-Origin
HTTP header in the response to the XMLHttpRequest.
If you end up with an XMLHttpRequest having status=0
and statusText=null
, it means that the request was not allowed to be performed. It was UNSENT
. A likely cause for this is when the XMLHttpRequest
origin (at the creation of the XMLHttpRequest) has changed when the XMLHttpRequest is then open()
. This case can happen for example when one has an XMLHttpRequest that gets fired on an onunload event for a window: the XMLHttpRequest gets in fact created when the window to be closed is still there, and then the request is sent (ie open()
) when this window has lost its focus and potentially different window has gained focus. The way to avoid this problem is to set a listener on the new window "activate" event that gets set when the old window has its "unload" event fired.
Instantiating XMLHttpRequest
from a JavaScript module or an XPCOM component works a little differently; it can't be instantiated using the XMLHttpRequest()
constructor. The constructor is not defined inside components and the code results in an error. The best way to work around this is to use the XPCOM component constructor.
const XMLHttpRequest = Components.Constructor("@mozilla.org/xmlextras/xmlhttprequest;1", "nsIXMLHttpRequest");
Unfortunately in versions of Gecko prior to Gecko 16 there is a bug which can cause requests created this way to be cancelled for no reason. If you need your code to work on Gecko 15 or earlier, you can get the XMLHttpRequest constructor from the hidden DOM window like so.
const { XMLHttpRequest } = Components.classes["@mozilla.org/appshell/appShellService;1"] .getService(Components.interfaces.nsIAppShellService) .hiddenDOMWindow; var oReq = new XMLHttpRequest();