XHR/AJAX
Raw JS XMLHttpRequest` or abstraction (e.g. JQuery AJAX - Asynchronous JavaScript and XML requests).
const req = new XMLHttpRequest();
req.addEventListener("load", (response) => ...
req.open("GET", "http://example.com");
req.send();
How are multiple requests handled? TODO UNCLEAR
Event loop pattern (concurrency) is used - instead of executing all processes at once, it does things one at a time and reacting to events that happen.
(Parallelism = doing lots of things at once; concurrency = dealing with lots of things at once)
Once the response is received, it is pushed to the event queue and if there is an opening in the JS call stack, the event handler is called.
Fetch
Introduced 2017, supports promises/async.
fetch("http://example/com")
.then(res => res.json())
.then(obj => console.log(obj))
.catch(err => console.log(err));
CORS: Cross Origin Resource Sharing
By default, XHR requests can only be made to the same origin that the script is hosted on.
The server of the requested content can optionally allow send some headers to allow this, which the browser must support and enforce.
Origin: protocol (HTTP/HTTPS) + domain + port
Forbidden request-headers are those that cannot be modified by XHR. These include:
Proxy-*Sec-*Access-Control-Request-HeadersAccess-Control-Request-MethodOriginHostContent-LengthCookieCookie2
Forbidden response-headers cannot be read by XHR:
Set-CookieSet-Cookie2
Before a XHR request is sent, the browser makes a preflight request using the HTTP OPTIONS method, to which the server should respond with some headers:
Access-Control-Allow-Origin: origin that can request the resource. Can be*, although this disables cookiesAccess-Control-Allow-Methods: comma-separated list of allowed HTTP methodsAccess-Control-Max-Age: number of seconds the response of a preflight request can be cachedAccess-Control-Allow-Credentials: true: cookies sent if trueAccess-Control-Allow-Headers: request headers the JS can modify- Required if browser sends
Access-Control-Request-Headerswith the headers the JS is trying to modify Accept,Accept-Language,Content-Language, andContent-Typeare safe headers and always allowed
- Required if browser sends
Access-Control-Expose-Headers: response headers the JS can read- Safe headers:
Cache-Control,Content-Language,Content-Length,Content-Type,Expires,Last-ModifiedandPragma
- Safe headers:
An old workaround: JSON-P (JSON with padding). Request a <script> from another origin, then a function/variable defined in the script can be called.
WebSockets
Persistent 2-way communication.
Client sends GET request to specific endpoint with a few headers (e.g. Connection: Upgrade, Upgrade: websocket, Sec-WebSocket-Key/-Protocol/-Version) to which the server response with a 101 (switching protocols) and a few more headers. After this handshake, it switches to using WebSocket.
Some NPM packages fallback to HTTP if it is not supported. With the ws package:
const WebSocket = require("ws");
const ws = new WebSocket("ws://example.com/path");
ws.on("open", () => ws.send("A"));
ws.on("message", msg => console.log(msg));