Chapter 3: Network requests
3.1 Fetch
JavaScript can send network requests to the server and load new information whenever it’s needed.
AJAX: Asynchronous JavaScript And XML
url
options
: method, headers, etc.The promise resolves with an object of the built-in
Response
class as soon as the server responds with headers. The promise rejects if the fetch was unable to make HTTP-request.status
: HTTP status codeok
: boolean,true
if code is 200-299Response
provides multiple promise-based methods to access the body in various.response.text()
response.json()
response.formData()
response.blob()
response.arrayBuffer()
response.body
:ReadableStream
object
We can choose only one body-reading method.
Headers
There’s a list of forbidden HTTP headers that we can’t set: Accept-Encoding
, Connection
, Content-Length
, Keep-Alive
, etc.
POST requests
method
:POST
body
: one of the following:string
FormData
Blob
/BufferSource
URLSearchParams
3.2 FormData
If HTML form
element is provided, it automatically captures its fields. It has a special type: Content-Type: multipart/form-data
.
formData.append(name, value)
: add a form field with the givenname
andvalue
.formData.append(name, blob, fileName)
: add afile
fieldformData.delete(name)
formData.get(name)
formData.has(name)
formData.set(name, value)
: remove othername
and add the new one (guaranteed unique)
3.3 Fetch: Download progress
The fetch
method allows to track download progress.
response.body
gives full control over the reading process, and we can count how much is consumed at any moment.
3.4 Fetch: Abort
AbortController
can be used to abort not only fetch, but other asynchronous tasks as well.
Create a controller.
It has a single method abort()
, and a single property signal
.
When abort()
is called:
abort
event triggers oncontroller.signal
.controller.signal.aborted
property becomestrue
.Pass the
signal
property tofetch
option.
To abort, call
controller.abort()
. Its promise rejects with an errorAbortError
.
AbortController
is scalable, it allows to cancel multiple fetches at once.
3.5 Fetch: Cross-Origin Requests
If we send a fetch
request to another web-site, it will probably fail.
Cross-origin requests require special headers from the remote side.
Simple requests
A simple request is a request that satisfies two conditions: 1. GET, POST or HEAD 2. Headers: Accept
, Accept-Language
, Content-Language
, Content-Type
(application/x-www-form-urlencoded
, multipart/form-data
, or text/plain
)
A “simple request” can be made with a <form>
or a <script>
, without any special methods.
CORS for simple requests
Request
Response
If the Access-Control-Allow-Origin
contains the origin or equals *
, the response is successful, otherwise an error.
Because Referer
is unreliable (can be modified or removed by fetch
), Origin
was invented, and the correctness of that header is ensured by the browser.
Response headers
For cross-origin request, by default JavaScript may only access simple response headers:
Cache-Control
Content-Language
Content-Type
Expires
Last-Modified
Pragma
To grant JavaScript access to any other response header, the server must send Access-Control-Expose-Headers
header.
Non-simple requests
A preflight request uses method OPTIONS
, no body and two headers:
Access-Control-Request-Method
: the method of the non-simple request.Access-Control-Request-Headers
: a comma-separated list of its non-simple HTTP-headers.
If the server agrees to serve the requests, then it should respond with empty body, status 200 and headers:
Access-Control-Allow-Method
Access-Control-Allow-Headers
Access-Control-Max-Age
: a number of seconds to cache the permissions.
Then the actual request is sent, the previous simple scheme is applied.
Credentials
A cross-origin request by default does not bring any credentials (cookies or HTTP authentication).
Request
Response
Access-Control-Allow-Origin
is prohibited from using *
for requests with credentials.
3.6 Fetch API
referrer, referrerPolicy
The referrer option allows to set any Referer
within the current origin or remove it.
The referrerPolicy
option sets general rules for Referer
.
"no-referrer-when-downgrade"
: Do not sendReferer
when we send a request from HTTPS to HTTP.no-referrer
origin
origin-when-cross-origin
: Send origin asReferer
when we send a cross-origin request.same-origin
: Send full Referer to the same origin, but no Referer for cross-origin requests.strict-origin
: Send origin asReferer
, but don’t send it for downgrade requests.strict-origin-when-cross-origin
: For same-origin send full Referer, for cross-origin send only origin, but don’t send it for downgrade requests.unsafe-url
: Always send full url inReferer
.
mode
The mode
option is a safe-guard that prevents occasional cross-origin requests:
cors
: the default, cross-origin requests are allowedsame-origin
: cross-origin requests are forbiddenno-cors
credentials
The credentials option specifies whether fetch should send cookies
and HTTP-Authorization
headers with the request.
same-origin
: the default, don’t send for cross-origin requestsinclude
: always send.omit
: never send.
cache
By default, fetch
requests make use of standard HTTP-caching. It uses Expires
, Cache-Control
headers, sends If-Modified-Since
, etc.
default
no-store
reload
no-cache
force-cache
only-if-cached
redirect
follow
error
: throw error in case of HTTP-redirect.manual
: don’t follow HTTP-redirect, butresponse.url
will be the new URL, andresponse.redirected
will betrue
.
integrity
The integrity
option allows to check if the response matches the known-ahead checksum. (SHA-256, SHA-384, and SHA-512)
keepalive
The keepalive
option indicates that the request may outlive the webpage that initiated it.
Normally, when a document is unloaded, all associated network requests are aborted. But keepalive
option tells the browser to perform the request in background, even after it leaves the page.
The body limit for
keepalive
requests is 64kb.We can’t handle the response if the document is unloaded.
3.7 URL objects
Creating a URL
url
: full URL or only path.base
: if set andurl
argument has only path, then the full URL is generated.
href
: the full url, same asurl.toString()
.protocol
: example:https
search
: a string of parameters, starts with the question mark?
.hash
: starts with the hash character#
.
SearchParams
Parameters need to be encoded if they contain spaces, non-latin letters, etc.
append(name, value)
delete(name)
get(name)
getAll(name)
has(name)
set(name, value)
sort()
Encoding
Encoding strings
encodeURI
: only characters that are totally forbidden in URL.decodeURI
encodeURIComponent
: forbidden characters and#, $, &, +, ,, /, :, ;, =, ?, @
.decodeURIComponent
3.8 XMLHttpRequest
In modern web-development XMLHttpRequest
is used for three reasons:
Historical reasons
Support old browsers without polyfills
Features that are not supported by
fetch
, such as tracking upload progress
The basics
Create
XMLHttpRequest
:
Initialize it:
method
: HTTP-methodURL
async
user
,password
Send it out:
Listen to
xhr
events for response.load
: triggers when the request is complete (even if HTTP status is like 400 or 500) and the response is downloaded.error
progress
: triggers periodically while the response is being downloaded, reports how much has been downloaded.
Once the server has responded, xhr
has these properties:
status
statusText
: example:OK
,NotFound
,Forbidden
response
We can also specify a timeout using the corresponding property:
xhr.responseType
""
: stringtext
: stringarraybuffer
blob
document
: XMLjson
xhr.readyState
We can track them using readystatechange
event. State 3
repeats every time a data packet is received over the network.
To terminate the request, call xhr.abort()
.
Synchronous requests
If in the open
method the third parameter async
is set to false
, the request is made synchronously. JavaScript execution pauses at send()
and resumes when the response is received.
However, if a synchronous call takes too much time, the browser may suggest to close the “hanging” webpage.
HTTP-headers
Several headers are managed exclusively by the browser, e.g. Referer
and Host
. It can’t undo setRequestHeader
.
POST, FormData
To make a POST request, we can use the built-in FormData
object, which is sent with multipart/form-data
encoding.
Upload progress
The progress
event triggers only on the downloading stage. We can use xhr.upload
to track upload events.
It generates these events:
loadstart
– upload started.progress
– triggers periodically during the upload.abort
– upload aborted.error
– non-HTTP error.load
– upload finished successfully.timeout
– upload timed out (if timeout property is set).loadend
– upload finished with either success or error.
3.9 Resumable file upload
Not-so-useful progress event
The event triggers when the data is sent, instead of receving by the server. Maybe it was buffered by a local network proxy, or maybe the remote server process just died and couldn’t process them.
Algorithm
Create an id to uniquely identify the file.
Send a request to the server, asking how many bytes it already has.
Use
Blob
methodslice
to send the file from the break point.
3.10 Long polling
Long polling is the simplest way of having persistent connection with server, that doesn’t use any specific protocol like WebSocket or Server Side Events.
Regular polling
The simplest way to get new information from the server is periodic polling.
Messages are passed with a delay up to the period.
The server may have too many requests to handle.
Long pooling
Long polling works great in situations when messages are rare.
Every message is a separate request, supplied with headers and authentication overhead.
A request is sent to the server.
The server doesn’t close the connection until it has a message to send.
When a message appears – the server responds to the request with it.
The browser makes a new request immediately.
3.11 WebSocket
The WebSocket
protocol provides a way to exchange data between browser and server via a persistent connection.
A simple example
Use wss://
protocol is encrypted and more reliable than ws://
.
Events
open
– connection established,message
– data received,error
– websocket error,close
– connection closed.
Opening a websocket
When new WebSocket(url)
is created, it starts connecting immediately.
Here’s an example of browser headers for request:
Origin
: It allows the server to decide whether or not to talkWebSocket
with this website.Connection: Upgrade
: The signal to change to protocol.Upgrade: websocket
: The requested protocol.Sec-WebSocket-Key
: Random security key.Sec-WebSocket-Version
: WebSocket protocol version. (Current: 13)
The server should send code 101
response:
Then the connection is made. WebSocket handshake can’t be emulated.
Extensions and subprotocols
The additional headers Sec-WebSocket-Extensions
and Sec-WebSocket-Protocol
describe extensions and subprotocols.
Sec-WebSocket-Extensions: deflate-frame
: the browser supports data compression.Sec-WebSocket-Protocol: soap, wamp
: we’d like to transfer the data in SOAP or WAMP ("The WebSocket Application Messaging Protocol") protocols.
The server should respond with a list of protocols and extensions that it agrees to use.
Data transfer
WebSocket communication consists of “frames” – data fragments, that can be sent from either side, and can be of several kinds:
text frames
binary data frames
ping/pong frames: used to check the connection (sent by server and responded automatically by browser)
connection close frame
WebSocket .send()
method can send either text or binary data.
When we receive the data, text always comes as string. And for binary data, we can choose between Blob
and ArrayBuffer
formats.
Rate limiting
The socket.bufferedAmount
property stores how many bytes are buffered at this moment, waiting to be sent over the network.
Connection close
code
: a special WebSocket closing code.reason
: a string that describes the reason of closing.
Most common codes:
1000
: the default closure1006
: connection was lost (can't be sent manually)1001
: the party is going away (server shuts down or user leaves the page)1009
: the message is too big to process1011
: unexpected error on server
Connection state
There's the socket.readyState
property with values:
0
: CONNECTING1
: OPEN2
: CLOSING3
: CLOSED
3.12 Server Sent Events
The Server-Sent Events
specification describes a built-in class EventSource
, that keeps connection with the server and allows to receive events from it.
It's simpler than WebSocket
:
Only server sends data
Only text
Regular HTTP protocol
Auto-reconnect
Getting messages
To start receiving messages, we just need to create new EventSource(url)
.
The server should respond with status 200 and the header Content-Type: text/event-stream
.
A message text goes after
data:
, the space after the colon is optional.Messages are delimited with double line breaks
\n\n
.To send a line break
\n
, we can immediately send one more data.
Cross-origin requests
EventSource
supports cross-origin requests. The remote server will get the Origin
header and must respond with Access-Control-Allow-Origin
to proceed.
Reconnection
There’s a small delay between reconnections, a few seconds by default. The server can set the recommended delay using retry:
in response.
If the browser knows that there’s no network connection at the moment, it may wait until the connection appears, and then retry.
If the server wants the browser to stop reconnecting, it should respond with HTTP status
204
.If the browser wants to close the connection, it should call
eventSource.close()
.
Message id
When a connection breaks due to network problems, either side can’t be sure which messages were received. To correctly resume the connection, each message should have an id
field.
When a message with id:
is received, the browser:
Sets the property
eventSource.lastEventId
to its value.Sends the header
Last-Event-ID
with thatid
when reconnecting.
Connection status: readyState
The EventSource
object has readyState
property.
0
: Connecting1
: Open2
: Closed
Event types
message
– a message received, available asevent.data
.open
– the connection is open.error
– the connection could not be established.
The server may specify another type of event with event: ...
at the event start.
To handle custom events, we must use addEventListener
:
Last updated