XMLHttpRequest
2022.06.20
XMLHttpRequest in JavaScript
#JavaScript#basics
use client /components/post/reExport XMLHttpRequest 2022.06.20 JavaScript ],
imgUrl: ,
desc: ,
body: (
<>
<ul>
<li>XMLHttpRequest is a built-in browser object that allows to make HTTP requests in JavaScript</li>
<li>Can operate on any data, not only in XML</li>
<li>Can upload/download files, track progress and much more</li>
<li><Lnk path= >Fetch</Lnk> somewhat deprecates XMLHttpRequest</li>
</ul>
<H>Used for</H>
<ul>
<li>support existing scripts with XMLHttpRequest</li>
<li>support old browsers</li>
<li>need something that fetch can’t do yet, e.g. to track upload progress</li>
</ul>
<H>Create</H>
<Code block jsx>{ https://google.com }</Code>
<ul>
<li><code>method</code> HTTP-method. Usually </li>
<li><code>URL</code> the URL to request, a string, can be URL object</li>
<li><code>async</code> if explicitly set to false, then the request is synchronous, we’ll cover that a bit later</li>
<li><code>user</code>, <code>password</code> login and password for basic HTTP auth (if required)</li>
</ul>
<Code block jsx>{ https://google.com/search ) // https://google.com/search?q=test+me%21
xhr.open( , url)
xhr.send([body])
}</i> request is complete (even if HTTP status is like 400 or 500), and the response is fully downloaded</li>
<li><i>{ }</i> request couldn’t be made, e.g. network down or invalid URL.</li>
<li><i>{ }</i> triggers periodically while the response is being downloaded, reports how much has been downloaded.</li>
<li><i>{ readystatechange }</i> old event, do not use it</li>
</ul>
<H>Properties</H>
<ul>
<li><Code>xhr.status</Code> HTTP status code (a number): 200, 404, 403 and so on, can be 0 in case of a non-HTTP failure</li>
<li><Code>xhr.statusText</Code> HTTP status message: usually for 200, for 404, for 403 and so on</li>
<li><Code>xhr.response</Code> server response body</li>
<li><Code>xhr.responseText</Code> same, used in old scripts</li>
<li><Code>xhr.responseXML</Code> used in old scripts</li>
<li><Code>xhr.timeout = 10000</Code> timeout in ms, if the request does not succeed in 10s, it gets canceled and timeout event triggers</li>
<li><Code>xhr.responseType = </Code> property to set the response format, get as string - (default)</li>
<li><Code>xhr.responseType = </Code> get as string</li>
<li><Code>xhr.responseType = </Code> get as ArrayBuffer (for binary data)</li>
<li><Code>xhr.responseType = </Code> get as Blob (for binary data)</li>
<li><Code>xhr.responseType = </Code> get as XML document (can use XPath and other XML methods) or HTML document (based on the MIME type of the received data)</li>
<li><Code>xhr.responseType = </Code> get as JSON (parsed automatically)</li>
<li><Code>xhr.readyState</Code> XMLHttpRequest changes between states as it progresses</li>
<li><Code js>xhr.setRequestHeader(name, value)</Code> sets the request header with the given name and value</li>
<li><Code js>xhr.getResponseHeader(name)</Code> gets the response header with the given name (except Set-Cookie and Set-Cookie2)</li>
<li><Code js>xhr.getAllResponseHeaders()</Code> returns all response headers, except Set-Cookie and Set-Cookie2</li>
<li><Code js>xhr.withCredentials = true</Code> send cookies and HTTP-authorization to another origin</li>
</ul>
<H>Examples</H>
<Code block jsx>{ /article/xmlhttprequest/example/load Error \${xhr.status}: \${xhr.statusText}\ Done, got \${xhr.response.length} bytes\ Received \${event.loaded} of \${event.total} bytes\ Received \${event.loaded} bytes\ Request failed }</Code>
<Code block jsx>{ /article/xmlhttprequest/example/json
xhr.send()
xhr.onload = function() {
let responseObj = xhr.response // { Hello, world! }</Code>
<H>xhr.readyState</H>
<p><Code>xhr.readyState</Code> XMLHttpRequest changes between states as it progresses</p>
<ul>
<li><Code>xhr.readyState = 0</Code> initial state</li>
<li><Code>xhr.readyState = 1</Code> open called</li>
<li><Code>xhr.readyState = 2</Code> response headers received</li>
<li><Code>xhr.readyState = 3</Code> response is loading (a data packet is received)</li>
<li><Code>xhr.readyState = 4</Code> request complete</li>
<li>We can track state using readystatechange event</li>
<li>It is an old approach, do not use it</li>
</ul>
<Code block jsx>{ }</Code>
<Code block jsx>{ , xhr.statusText);
break;
case 1:
// OPENED, open() has been called.
console.log( , xhr.statusText);
break;
case 2:
// HEADERS_RECEIVED, send() has been called, and headers and status are available.
console.log( , xhr.statusText);
break;
case 3:
// LOADING, Downloading; responseText holds partial data.
console.log( , xhr.statusText);
console.log( + xhr.responseText.length + );
break;
case 4:
// DONE, The operation is complete.
console.log( , xhr.statusText);
const header = xhr.getResponseHeader( );
const headers = xhr.getAllResponseHeaders();
if (xhr.status == 200 || xhr.status == 304) {
var data = xhr.responseText;
console.log( );
console.dir(data);
} else {
console.log( + xhr.statusText);
}
break;
}
};
xhr.withCredentials = true;
xhr.responseType = ;
xhr.setRequestHeader( application/json );
xhr.send(null);
is set to , the request is made synchronously</li>
<li>JavaScript pauses at send() and resumes when the response is received</li>
</ul>
<Code block jsx>{ /article/xmlhttprequest/hello.txt Error \${xhr.status}: \${xhr.statusText}\ Request failed }</Code>
<H>HTTP-headers</H>
<Hs>setRequestHeader</Hs>
<Code block jsx>{ }</Code>
<ul>
<li>Sets the request header with the given name and value.</li>
<li>Several headers are managed exclusively by the browser, e.g. </li>
<li>Once the header is set, it’s set, can not overwrite it after</li>
</ul>
<Code block jsx>{ Content-Type application/json }</Code>
<Hs>getResponseHeader</Hs>
<Code block jsx>{ }</Code>
<p>Gets the response header with the given name (except Set-Cookie and Set-Cookie2).</p>
<Code block jsx>{ Content-Type }</Code>
<Hs>getAllResponseHeaders</Hs>
<ul>
<li>Returns all response headers, except Set-Cookie and Set-Cookie2</li>
<li>Headers are returned as a single line</li>
<li>The line break between headers is always </li>
<li>we can easily split it into individual headers</li>
<li>The separator between the name and the value is always a colon followed by a space </li>
</ul>
<Code block jsx>{ )
.reduce((result, current) => {
let [name, value] = current.split( )
result[name] = value
return result
}, {})
// headers[ }</Code>
<H>POST with FormData</H>
<p>To make a POST request, we can use the built-in FormData object.</p>
<Code block html>{ >
<input name= >
<input name= >
</form>
const formData = new FormData(document.forms.person) // pre-fill FormData from the form
formData.append( ) // add one more field
const xhr = new XMLHttpRequest()
xhr.open( /article/xmlhttprequest/post/user , surname: })
xhr.open( )
xhr.setRequestHeader( application/json charset=utf-8 }</Code>
<H>Upload progress</H>
<ul>
<li><code>xhr.upload</code> generates events and triggers them on uploading</li>
<li><code>xhr.upload = </code> upload started</li>
<li><code>xhr.upload = </code> triggers periodically during the upload</li>
<li><code>xhr.upload = </code> upload aborted</li>
<li><code>xhr.upload = </code> non-HTTP error</li>
<li><code>xhr.upload = </code> upload finished successfully</li>
<li><code>xhr.upload = </code> upload timed out (if timeout property is set)</li>
<li><code>xhr.upload = </code> upload finished with either success or error</li>
</ul>
<Code block jsx>{ Uploaded \${e.loaded} of \${e.total} bytes\ Upload finished successfully.\ Error during the upload: \${xhr.status}\ }</Code>
<Code block html>{ onchange= }</Code>
<Code block jsx>{ Uploaded \${e.loaded} of \${e.total}\ )
} else {
console.log( + this.status)
}
}
xhr.open( /article/xmlhttprequest/post/upload }</Code>
<H>Cross-origin requests</H>
<ul>
<li><i>XMLHttpRequest</i> can make cross-origin requests, using the same CORS policy as fetch</li>
<li>Just like fetch, it doesn’t send cookies and HTTP-authorization to another origin by default</li>
<li>To enable them, set xhr.withCredentials to true</li>
</ul>
<Code block jsx>{ http://anywhere.com/request