Fetch API tutorial
fetch()
It is an upgraded version of XMLHttpRequest, used to make HTTP requests in JavaScript scripts.
The browser provides this object natively. This article introduces its usage in detail.
1. Basic usage
fetch()
The function is basically the same as XMLHttpRequest, but there are three main differences.
(1)
fetch()
Promise is used and no callback function is used, so the writing method is greatly simplified and the writing is more concise.
(2)
fetch()
The modular design is adopted, and the API is scattered on multiple objects (Response object, Request object, Headers object), which is more reasonable; in contrast, the API design of XMLHttpRequest is not very good, input, output, and status are all In the same interface management, it is easy to write very confusing code.
(3)
fetch()
The data is processed through the data stream (Stream object), which can be read in blocks, which is conducive to improving website performance and reducing memory usage. It is very useful for scenarios where large files are requested or the network speed is slow.
The XMLHTTPRequest object does not support data streaming, all data must be stored in the cache, and block reading is not supported. You must wait for all of them to be obtained and then spit it out at once.
In terms of usage, it
fetch()
accepts a URL string as a parameter, sends a GET request to the URL by default, and returns a Promise object.
Its basic usage is as follows.
fetch(url) .then(...) .catch(...)
The following is an example to get JSON data from the server.
fetch('https://api.github.com/users/ruanyf') .then(response => response.json()) .then(json => console.log(json)) .catch(err => console.log('Request Failed', err));
In the above example, what is
fetch()
received
response
is a
Stream object
, which
response.json()
is an asynchronous operation, taking out all the content and converting it into a JSON object.
Promise can be rewritten using await syntax to make the semantics clearer.
async function getJSON() { let url = 'https://api.github.com/users/ruanyf'; try { let response = await fetch(url); return await response.json(); } catch (error) { console.log('Request Failed', error); } }
In the above example, the
await
statement must be placed
try...catch
inside, so as to catch the errors that may occur in the asynchronous operation.
await
The writing method
used
in the
following text,
the writing method not used
.then()
.
2. Response object: handle HTTP response
2.1 Synchronous properties of the Response object
fetch()
After the request is successful, you get a
Response object
.
It corresponds to the HTTP response of the server.
const response = await fetch(url);
As mentioned earlier, the data contained in the Response is read asynchronously through the Stream interface, but it also contains some synchronous attributes, which correspond to the header information (Headers) of the HTTP response, which can be read immediately.
async function fetchText() { let response = await fetch('/readme.txt'); console.log(response.status); console.log(response.statusText); }
In the above example, the
response.status
sum
response.statusText
is the synchronization attribute of Response, which can be read immediately.
The header information attributes are as follows.
Response.ok
Response.ok
The attribute returns a Boolean value, indicating whether the request is successful,
true
corresponding to the HTTP request status code 200 to 299,
false
corresponding to other status codes.
Response.status
Response.status
The attribute returns a number that represents the status code of the HTTP response (for example, 200, indicating a successful request).
Response.statusText
Response.statusText
The attribute returns a string that represents the status information of the HTTP response (for example, after the request is successful, the server returns “OK”).
Response.url
Response.url
The attribute returns the requested URL.
If the URL has a redirect, this attribute returns the final URL.
Response.type
Response.type
The attribute returns the requested type.
The possible values are as follows:
basic
: Ordinary request, that is, same-origin request.cors
: Cross-domain request.error
: Network error, mainly used for Service Worker.opaque
: If thefetch()
requestedtype
attribute is setno-cors
, this value will be returned, see the request section for details. Indicates that a simple cross-domain request is issued,<form>
the kind of cross-domain request similar to a form.opaqueredirect
: If thefetch()
requestedredirect
attribute is setmanual
, this value will be returned, see the request section for details.
Response.redirected
Response.redirected
The property returns a boolean value indicating whether the request has been redirected.
2.2 Determine whether the request is successful
fetch()
After sending the request, there is a very important point to note: only when there is a network error or cannot connect, an
fetch()
error will be reported. In other cases, an error will not be reported, but the request will be considered successful.
That is, even if the server returns a status code 4xx 5xx or,
fetch()
no error will be (i.e., does not go Promise
rejected
state).
Only by
Response.status
obtaining the true status code of the HTTP response
through the
attributes, can it be judged whether the request is successful.
Please see the example below.
async function fetchText() { let response = await fetch('/readme.txt'); if (response.status >= 200 && response.status < 300) { return await response.text(); } else { throw new Error(response.statusText); } }
In the above example,
response.status
only if the attribute is equal to 2xx (200~299), can the request be considered successful.
There is no need to consider the URL redirection (status code is 3xx), because
fetch()
the status code of the redirection will be automatically converted to 200.
Another method is to determine
response.ok
whether it is
true
.
if (response.ok) { // 请求成功 } else { // 请求失败 }
2.3 Response.headers property
The Response object also has an
Response.headers
attribute that points to a
Headers object
, which corresponds to all the headers of the HTTP response.
Headers objects can
for...of
be traversed
using
loops.
const response = await fetch(url); for (let [key, value] of response.headers) { console.log(`${key} : ${value}`); } // 或者 for (let [key, value] of response.headers.entries()) { console.log(`${key} : ${value}`); }
The Headers object provides the following methods to manipulate headers.
Headers.get()
: According to the specified key name, return the key value.Headers.has()
: Returns a Boolean value indicating whether a certain header is included.Headers.set()
: Set the specified key name as a new key value, if the key name does not exist, it will be added.Headers.append()
: Add a header.Headers.delete()
: Delete the header.Headers.keys()
: Return a traverser, which can traverse all key names in turn.Headers.values()
: Return a traverser, which can traverse all key values in turn.Headers.entries()
: Return a traverser, which can traverse all key-value pairs in turn ([key, value]
).Headers.forEach()
: Traverse the headers in turn, each header will execute the parameter function once.
Some of the above methods can modify the headers because they are inherited from the Headers interface. For HTTP responses, modifying the header is of little significance, and many headers are read-only, and browsers do not allow modification.
Among these methods, the most commonly used is
response.headers.get()
to read the value of a certain header.
let response = await fetch(url); response.headers.get('Content-Type') // application/json; charset=utf-8
Headers.keys()
The and
Headers.values()
methods are used to respectively traverse the key name and key value of the header.
// 键名 for(let key of myHeaders.keys()) { console.log(key); } // 键值 for(let value of myHeaders.values()) { console.log(value); }
Headers.forEach()
The method can also traverse all the key values and key names.
let response = await fetch(url); response.headers.forEach( (value, key) => console.log(key, ':', value) );
2.4 How to read content
Response
The object provides different reading methods according to the different types of data returned by the server.
response.text()
: Get a text string.response.json()
: Get the JSON object.response.blob()
: Obtain a binary Blob object.response.formData()
: Get the FormData form object.response.arrayBuffer()
: Obtain a binary ArrayBuffer object.
The above five read methods are all asynchronous and all return Promise objects. You must wait until the end of the asynchronous operation to get the complete data returned by the server.
response.text()
response.text()
Can be used to obtain text data, such as HTML files.
const response = await fetch('/users.html'); const body = await response.text(); document.body.innerHTML = body
response.json()
response.json()
It is mainly used to obtain the JSON data returned by the server. The examples have been given above.
response.formData()
response.formData()
Mainly used in Service Worker to intercept the form submitted by the user, modify some data, and then submit it to the server.
response.blob()
response.blob()
Used to obtain binary files.
const response = await fetch('flower.jpg'); const myBlob = await response.blob(); const objectURL = URL.createObjectURL(myBlob); const myImage = document.querySelector('img'); myImage.src = objectURL;
The above example reads a picture file
flower.jpg
and displays it on the web page.
response.arrayBuffer()
response.arrayBuffer()
Mainly used to obtain streaming media files.
const audioCtx = new window.AudioContext(); const source = audioCtx.createBufferSource(); const response = await fetch('song.ogg'); const buffer = await response.arrayBuffer(); const decodeData = await audioCtx.decodeAudioData(buffer); source.buffer = buffer; source.connect(audioCtx.destination); source.loop = true;
The above example is
response.arrayBuffer()
an
example of
obtaining an audio file
song.ogg
and then playing it online.
2.5 Response.clone()
The Stream object can only be read once, and it is gone after reading. This means that only one of the five reading methods in the previous section can be used, otherwise an error will be reported.
let text = await response.text(); let json = await response.json(); // 报错
The above example is used first
response.text()
, and the Stream is read.
If you call
response.json()
it
later
, there is no content to read, so an error is reported.
The Response object provides
Response.clone()
methods to create
Response
a copy of the object and implement multiple reads.
const response1 = await fetch('flowers.jpg'); const response2 = response1.clone(); const myBlob1 = await response1.blob(); const myBlob2 = await response2.blob(); image1.src = URL.createObjectURL(myBlob1); image2.src = URL.createObjectURL(myBlob2);
In the above example, a
response.clone()
copy of the Response object was copied, and then the same image was read twice.
The Response object also has a
Response.redirect()
method for redirecting the Response result to the specified URL.
This method is generally only used in Service Worker, so I won’t introduce it here.
2.6 Response.body attribute
Response.body
The property is the underlying interface exposed by the Response object and returns a ReadableStream object for user operations.
It can be used to read the content in chunks, and one of the applications is to display the progress of the download.
const response = await fetch('flower.jpg'); const reader = response.body.getReader(); while(true) { const {done, value} = await reader.read(); if (done) { break; } console.log(`Received ${value.length} bytes`) }
In the example above, the
response.body.getReader()
method returns a iterator.
The
read()
method of
this traverser
returns an object each time, representing the content block read this time.
The
done
attribute of
this object
is a boolean value, used to judge whether it has been read; the
value
attribute is an arrayBuffer array, which represents the content of the content block, and the
value.length
attribute is the size of the current block.
Third,
fetch()
the second parameter: custom HTTP request
fetch()
The first parameter is the URL, and the second parameter can also be accepted as a configuration object to customize the HTTP request sent out.
fetch(url, optionObj)
The above command
optionObj
is the second parameter.
The method, header, and data body of the HTTP request are all set in this object. Here are some examples.
(1) POST request
const response = await fetch(url, { method: 'POST', headers: { "Content-type": "application/x-www-form-urlencoded; charset=UTF-8", }, body: 'foo=bar&lorem=ipsum', }); const json = await response.json();
In the above example, three attributes are used in the configuration object.
method
: The method of HTTPPOST
requests,DELETE
, ,PUT
are arranged in this property.headers
: An object used to customize the header of the HTTP request.body
: The data body of the POST request.
Note that the header can not pass through some
headers
property, such as
Content-Length
,
Cookie
,
Host
and the like.
They are automatically generated by the browser and cannot be modified.
(2) Submit JSON data
const user = { name: 'John', surname: 'Smith' }; const response = await fetch('/article/fetch/post/user', { method: 'POST', headers: { 'Content-Type': 'application/json;charset=utf-8' }, body: JSON.stringify(user) });
In the above example, the header
Content-Type
should be set to
'application/json;charset=utf-8'
.
Because the default is to send plain text,
Content-Type
the default value is
'text/plain;charset=UTF-8'
.
(3) Submit the form
const form = document.querySelector('form'); const response = await fetch('/users', { method: 'POST', body: new FormData(form) })
(4) File upload
If there is a file selector in the form, you can use the way of writing in the previous example. The uploaded file is included in the entire form and submitted together.
Another method is to add files with scripts, construct a form, and upload, please see the example below.
const input = document.querySelector('input[type="file"]'); const data = new FormData(); data.append('file', input.files[0]); data.append('user', 'foo'); fetch('/avatars', { method: 'POST', body: data });
When uploading a binary file, there is no need to modify the header
Content-Type
, the browser will automatically set it.
(5) Upload binary data directly
fetch()
You can also upload binary data directly, and put the Blob or arrayBuffer data in the
body
attribute.
let blob = await new Promise(resolve => canvasElem.toBlob(resolve, 'image/png') ); let response = await fetch('/article/fetch/post/image', { method: 'POST', body: blob });
Fourth,
fetch()
the complete API of the configuration object
fetch()
The complete API of the second parameter is as follows.
const response = fetch(url, { method: "GET", headers: { "Content-Type": "text/plain;charset=UTF-8" }, body: undefined, referrer: "about:client", referrerPolicy: "no-referrer-when-downgrade", mode: "cors", credentials: "same-origin", cache: "default", redirect: "follow", integrity: "", keepalive: false, signal: undefined });
fetch()
The bottom layer of the request uses the
interface
of the
Request() object
, and the parameters are exactly the same, so the above API is also
Request()
the API.
Inside these properties,
headers
,
body
,
method
previously gave an example, the following is a description of other properties.
cache
cache
The attribute specifies how to handle the cache.
The possible values are as follows:
default
: The default value, first search for matching requests in the cache.no-store
: Directly request the remote server without updating the cache.reload
: Directly request the remote server and update the cache.no-cache
: Compare the server resource with the local cache, and use the server resource only when there is a new version, otherwise use the cache.force-cache
: Cache priority. Only when there is no cache, the remote server is requested.only-if-cached
: Only check the cache, if it does not exist in the cache, a 504 error will be returned.
mode
mode
The attribute specifies the requested mode.
The possible values are as follows:
cors
: The default value, allowing cross-domain requests.same-origin
: Only homologous requests are allowed.no-cors
: The request method is limited to GET, POST, and HEAD, and only a limited number of simple headers can be used. Cross-domain complex headers cannot be added, which is equivalent to the request that can be sent by submitting the form.
credentials
credentials
The attribute specifies whether to send a cookie.
The possible values are as follows:
same-origin
: The default value, cookies are sent when requesting from the same origin, but not when requesting across domains.include
: Regardless of the same-origin request or cross-domain request, cookies are always sent.omit
: Never send.
For cross-domain requests to send cookies, the
credentials
attribute
needs to be
set
include
.
fetch('http://another.com', { credentials: "include" });
signal
signal
The attribute specifies an AbortSignal instance to cancel the
fetch()
request, see the next section
for
details.
keepalive
keepalive
When the property is used to uninstall the page, it tells the browser to keep the connection in the background and continue to send data.
A typical scenario is that when the user leaves the web page, the script submits some statistical information about the user’s behavior to the server.
At this time, if the
keepalive
attribute
is not used
, the data may not be sent because the browser has already uninstalled the page.
window.onunload = function() { fetch('/analytics', { method: 'POST', body: "statistics", keepalive: true }); };
redirect
redirect
The attribute specifies the processing method of the HTTP jump.
The possible values are as follows:
follow
: Default value,fetch()
follow HTTP jump.error
: If a jump occurs,fetch()
an error will be reported.manual
:fetch()
Do not follow the HTTP redirect, but theresponse.url
attribute will point to the new URL, and theresponse.redirected
attribute will be changedtrue
. It is up to the developer to decide how to handle the redirect in the future.
integrity
integrity
The attribute specifies a hash value, which is used to check whether the data returned by the HTTP response is equal to the preset hash value.
For example, when downloading a file, check whether the SHA-256 hash value of the file matches to ensure that it has not been tampered with.
fetch('http://site.com/file', { integrity: 'sha256-abcdef' });
referrer
referrer
The attribute is used to set
fetch()
the
referer
header of the
request
.
This attribute can be any string, or it can be set to an empty string (that is, no
referer
header
is sent
).
fetch('/page', { referrer: '' });
referrerPolicy
referrerPolicy
Attributes are used to set
Referer
the rules of the header.
The possible values are as follows:
no-referrer-when-downgrade
: The default value. TheReferer
header is always sent unless it is not sent when requesting HTTP resources from an HTTPS page.no-referrer
: Do not sendReferer
headers.origin
:Referer
The header only contains the domain name, not the complete path.origin-when-cross-origin
: The same-origin requestReferer
header contains the complete path, and the cross-domain request only contains the domain name.same-origin
: Cross-domain requests are not sentReferer
, and requests from the same source are sent.strict-origin
:Referer
The header only contains the domain name, and theReferer
header is not sent when the HTTPS page requests HTTP resources .strict-origin-when-cross-origin
: TheReferer
header contains the full path for the same-origin request, and only the domain name for the cross-domain request. This header is not sent when the HTTPS page requests HTTP resources.unsafe-url
: No matter what the situation, always send theReferer
header.
5. Cancellation
fetch()
request
fetch()
After the request is sent, if you want to cancel halfway, you need to use the
AbortController
object.
let controller = new AbortController(); let signal = controller.signal; fetch(url, { signal: controller.signal }); signal.addEventListener('abort', () => console.log('abort!') ); controller.abort(); // 取消 console.log(signal.aborted); // true
In the above example, first create a new AbortController instance, and then send a
fetch()
request. The
signal
properties of the
configuration object
must specify to receive the signal sent by the AbortController instance
controller.signal
.
controller.abort()
Method is used to signal cancellation.
At this time, an
abort
event
will be triggered
. This event can be monitored, or it can be
controller.signal.aborted
judged
by
attributes whether the cancellation signal has been sent.
The following is an example of automatically canceling the request after 1 second.
let controller = new AbortController(); setTimeout(() => controller.abort(), 1000); try { let response = await fetch('/long-operation', { signal: controller.signal }); } catch(err) { if (err.name == 'AbortError') { console.log('Aborted!'); } else { throw err; } }
6. Reference link
- Network requests: Fetch
- node-fetch
- Introduction to fetch()
- Using Fetch
- Javascript Fetch API: The XMLHttpRequest evolution
(over)