fetch()
is an upgraded version of XMLHttpRequest
used to make HTTP
requests inside JavaScript
scripts.
The browser provides this object natively. This article describes its usage in detail.
1. Basic usage
The function of fetch()
is basically the same as XMLHttpRequest
, but with three main differences.
fetch()
usesPromise
and does not use a callback function, so it is much simpler to write and more concise.- The modular design of
fetch()
, withAPI
spread over multiple objects (Response
object,Request
object,Headers
object), is more reasonable; in contrast, theAPI
design ofXMLHttpRequest
is not very good, with input, output and state all managed in the same interface, making it easy to write very confusing code. fetch()
processes data through a data stream (Stream
object), which can be read in chunks, which is good for improving website performance and reducing memory usage, and is quite useful for requesting large files or slow internet scenarios. TheXMLHTTPRequest
object does not support data streams, all the data must be placed in the cache, does not support reading in chunks, you must wait until you get it all and then spit it out at once.
In terms of usage, fetch()
accepts a URL string as an argument, makes a GET
request to that URL by default, and returns a Promise
object. Its basic usage is as follows.
Here is an example to get JSON
data from the server.
In the above example, the response
received by fetch()
is a Stream
object, and response.json()
is an asynchronous operation that takes out all the content and converts it to a JSON
object.
Promise
can be rewritten using the await
syntax to make the semantics clearer.
In the example above, the await
statement must be placed inside the try.... .catch
inside so as to catch any errors that may occur in the asynchronous operation.
The latter are written in the await
style, not in the .then()
style.
2. the Response object: handling HTTP responses
2.1 Synchronization Properties of Response Object
When a fetch()
request succeeds, a Response object is obtained. It corresponds to the HTTP
response from the server.
|
|
As mentioned before, Response
contains data that is read asynchronously through the Stream
interface, but it also contains some synchronous properties that correspond to the header information (Headers
) of the HTTP
response, which can be read immediately.
In the above example, response.status
and response.statusText
are the synchronization properties of Response
, which can be read immediately.
The header information attributes are as follows.
Response.ok
The Response.ok
property returns a boolean value indicating whether the request was successful or not, true
corresponding to the status codes 200
to 299
for HTTP
requests and false corresponding to the other status codes.
Response.status
The Response.status
property returns a number indicating the status code of the HTTP
response (e.g. 200
, for a successful request).
Response.statusText
The Response.statusText
property returns a string indicating the status of the HTTP
response (for example, the server returns “OK” after a successful request).
Response.url
The Response.url
property returns the URL
of the request. If there is a jump in the URL
, this property returns the final URL
. (return “OK”).
Response.type
The Response.type
property returns the type of the request. The possible values are as follows.
basic
: normal request, i.e. homologous request.cors
: cross-domain request.error
: network error, mainly used forService Worker
.opaque
: This value is returned if thetype
attribute of thefetch()
request is set tono-cors
, see the request section for details. Indicates that a simple cross-domain request is being made, similar to the kind of cross-domain request made by<form>
forms.opaqueredirect
: This value is returned if theredirect
attribute of thefetch()
request is set tomanual
, see the request section for details.
Response.redirected
The Response.redirected
property returns a boolean value indicating whether the request has been redirected.
2.2 Determining whether a request is successful or not
After fetch()
issues a request, there is an important note: fetch()
will only report an error if there is a network error, or if the connection cannot be made, but in all other cases it will not report an error and will consider the request successful.
This means that fetch()
will not report an error even if the status code returned by the server is 4xx
or 5xx
(i.e. Promise
will not change to the rejected
state).
The only way to tell if a request is successful is to get the real status code of the HTTP
response through the Response.status
property. See the following example.
In the above example, the response.status
property is only equal to 2xx
(200~299) to determine the success of the request. There is no need to consider URL bounces (with status code 3xx
), because fetch()
will automatically turn the bounced status code to 200
.
Another way is to determine if response.ok
is true
.
2.3 Response.headers property
The Response
object also has a Response.headers
property, which points to a Headers
object corresponding to all headers of the HTTP
response.
The Headers object can be traversed using a for. . of loop to iterate through them.
The Headers
object provides the following methods to manipulate headers.
Headers.get()
: Returns the key value, based on the specified key name.Headers.has()
: returns a boolean value indicating whether or not a header is contained.Headers.set()
: sets the specified key name to the new key value, or adds it if it does not exist.Headers.append()
: add the header.Headers.delete()
: delete the header.Headers.keys()
: return a traverser that iterates through all the key names in order.Headers.values()
: returns a traverser that iterates through all the key values in order.Headers.entries()
: returns a traverser that iterates through all key-value pairs ([key, value]) in order.Headers.forEach()
: iterates through the headers in turn, executing the argument function once for each header.
Some of the methods above can modify headers because they inherit from the Headers
interface. For HTTP
responses, it makes little sense to modify headers, and many headers are read-only, so browsers do not allow modifications.
The most common of these methods is response.headers.get()
, which is used to read the value of a header.
The Headers.keys()
and Headers.values()
methods are used to iterate over the key names and key values of the headers, respectively.
The Headers.forEach()
method can also iterate through all the keys and key names.
2.4 Methods for reading content
The Response
object provides different read methods depending on the different types of data returned by the server.
response.text()
: get the text string.response.json()
: get JSON object.response.blob()
: get the binary Blob object.response.formData()
: get the FormData form object.response.arrayBuffer()
: get the binary ArrayBuffer object.
The 5
read methods above are all asynchronous and return a Promise
object. You must wait until the asynchronous operation is finished to get the complete data returned by the server.
response.text()
response.text()
can be used to get text data, such as HTML
files.
response.json()
response.json()
is mainly used to get the JSON
data returned by the server, which has been given as an example earlier.
response.formData()
response.formData()
is mainly used in the Service Worker
to intercept user-submitted forms, modify some data, and then submit them to the server.
response.blob()
response.blob()
is used to get the binary file.
The above example reads the image file flower.jpg and displays it on the web page.
response.arrayBuffer()
response.arrayBuffer()
is mainly used to get the streaming file.
|
|
The above example is response.arrayBuffer()
to get the audio file song.ogg and then play it online.
2.5 Response.clone()
The Stream
object can only be read once, and when it’s done, it’s gone. This means that only one of the five read methods in the previous section can be used, otherwise an error will be reported.
The above example uses response.text()
first, and then the Stream
is read out. If you call response.json()
later, there is no more content to read, so an error is reported.
The Response
object provides the Response.clone()
method to create a copy of the Response
object for multiple reads.
In the above example, response.clone()
makes a copy of the Response
object, and then reads the same image twice.
The Response
object also has a Response.redirect()
method that redirects the Response
result to the specified URL
. This method is generally only used inside the Service Worker
, so it is not described here.
2.6 The Response.body property
The Response.body
property is the underlying interface exposed by the Response
object, returning a ReadableStream
object for the user to manipulate.
It can be used to read content in chunks, and one application is to display the progress of a download.
In the above example, the response.body.getReader()
method returns a traverser. The read()
method of this traverser returns one object at a time, representing the block of content read this time.
The done
property of this object is a Boolean value that determines whether the read is complete; the value
property is an arrayBuffer
array that represents the contents of the block, and the value.length
property is the size of the current block.
3. the second parameter of fetch(): custom HTTP request
The first argument to fetch()
is the URL
, and it can also accept a second argument as a configuration object to customize the outgoing HTTP
request.
|
|
The optionObj
of the above command is the second parameter.
The method, header, and data body of the HTTP request are set inside this object. Here are some examples.
POST request
In the above example, the configuration object uses three properties.
method
: method of the HTTP request, POST, DELETE, PUT are set in this property.headers
: an object to customize the headers of the HTTP request.body
: the data body of the POST request.
Note that some headers cannot be set via the headers
attribute, such as Content-Length
, Cookie
, Host
and so on. They are automatically generated by the browser and cannot be modified.
Submit JSON data
In the above example, the header Content-Type
should be set to ‘application/json;charset=utf-8’. Because the default sent is plain text, the default value of Content-Type
is ’text/plain;charset=UTF-8’.
Submission Form
File upload
If there is a file selector inside the form, you can use the previous example to write the uploaded file to be included in the whole form and submit it together.
Another way is to add files with a script to construct a form for uploading, see the example below.
When uploading binary files, you don’t need to change the Content-Type
in the header, the browser will set it automatically.
Upload binary data directly
fetch()
can also upload binary data directly, putting Blob
or arrayBuffer
data inside the body
property.
4. The full API for the fetch() configuration object
The full API
for the second parameter of fetch()
is as follows.
|
|
The underlying fetch()
request uses the interface of the Request()
object with exactly the same parameters, so the API
above is also the API
of Request()
.
Among these properties, headers
, body
, and method
have been given as examples earlier, and the following is an introduction to the other properties.
cache
The cache
property specifies how the cache is handled. The possible values are as follows.
default
: default value, look for matching requests inside the cache first.no-store
: request the remote server directly, and do not update the cache.reload
: request the remote server directly and update the cache.no-cache
: compare server resources with local cache, use server resources only if there is a new version, otherwise use cache.force-cache
: cache takes precedence and requests the remote server only if no cache exists.only-if-cached
: only check the cache, if it does not exist inside the cache, a 504 error will be returned.
mode
The mode
attribute specifies the mode of the request. The possible values are as follows.
cors
: default value, cross-domain requests are allowed.same-origin
: only same-origin requests are allowed.no-cors
: request methods are limited toGET
,POST
andHEAD
, and only a limited number of simple headers can be used, no cross-domain complex headers can be added, equivalent to the requests that can be made by submitting a form.
credentials
The credentials
attribute specifies whether to send cookies
. The possible values are as follows.
same-origin
: default value, sendCookie
for same-origin requests, not for cross-domain requests.include
:Cookie
is sent for both same-origin and cross-domain requests.omit
: no cookie is sent for all requests.
Cross-domain requests send Cookie
and require the credentials
property to be set to include
.
signal
The signal
attribute specifies an AbortSignal
instance to cancel the fetch()
request, as detailed in the next section.
keepalive
The keepalive
property is used when the page is offloaded to tell the browser to stay connected in the background and continue sending data.
A typical scenario is when a user leaves a web page and the script submits some statistics about the user’s behavior to the server. At this point, if the keepalive
property is not used, the data may not be sent because the browser has unloaded the page.
redirect
The redirect
attribute specifies the method of handling HTTP
jumps. The possible values are as follows.
follow
: default value,fetch()
followsHTTP
jumps.error
:fetch()
reports an error if a jump occurs.manual
:fetch()
does not follow HTTP jumps, but theresponse.url
property will point to the newURL
and theresponse.redirected
property will change totrue
, leaving it up to the developer to decide how to handle subsequent jumps.
integrity
The integrity
attribute specifies a hash value to check that the data returned by the HTTP
response is equal to this pre-defined hash value.
For example, when downloading a file, check that the SHA-256
hash of the file matches to ensure that it has not been tampered with.
referrer
The referrer
attribute is used to set the referer
header for fetch()
requests.
This attribute can be any string, or it can be set to an empty string (i.e. no referer
header is sent).
referrerPolicy
The referrerPolicy
property is used to set the rules for the Refererer
header. The possible values are as follows.
no-referrer-when-downgrade
: default, always sends the Referer header, unless it is not sent when requesting HTTP resources from HTTPS pages.no-referrer
: do not send the Referer header.origin
: The Referer header contains only the domain name, not the full path.origin-when-cross-origin
: same origin request Referer header contains full path, cross-domain request contains only domain name.same-origin
: cross-domain request does not send the Referer, same-origin request sends it.strict-origin
: The Referer header contains only the domain name, and the Referer header is not sent for HTTPS pages requesting HTTP resources.strict-origin-when-cross-origin
: The Referer header contains the full path for same-origin requests, and only the domain name for cross-domain requests; it is not sent when HTTPS pages request HTTP resources.unsafe-url
: always send the Referer header regardless of the case.
5. Cancel fetch() request
After the fetch()
request is sent, if you want to cancel it in the middle, you need to use the AbortController
object.
In the above example, first a new AbortController
instance is created, then a fetch()
request is sent, and the signal
property of the configuration object must specify to receive the signal controller.signal
from the AbortController
instance.
The controller.abort()
method is used to send the abort signal. This triggers the abort
event, which can be listened to, or the controller.signal.aborted
property can be used to determine if the cancel signal has been sent.
Here is an example of an automatic request cancellation after 1 second.
6. Reference Links
- Network requests: Fetch
- node-fetch
- Introduction to fetch()
- Using Fetch
- Javascript Fetch API: The XMLHttpRequest evolution
Reference https://www.ruanyifeng.com/blog/2020/12/fetch-tutorial.html