Cross-Origin requests fetch request to another web-site probably fails origin – a domain/port/protocol Cross-origin requests are sent to another domain (even a subdomain) or protocol or port Cross-origin requests are allowed, but with explicit allowance by the server, expressed in special headers that policy is called CORS : C ross- O rigin R esource S haring CORS exists to protect the internet from hackers There are two types of cross-origin requests: safe requests & all others Safe requests A request is safe if it satisfies two conditions... has one of methods: GET or POST or HEAD allowed custom headers: Accept , Accept-Language , Content-Language , Content-Type with the value application/x-www-form-urlencoded , multipart/form-data or text/plain 'safe' requests are sent right away, with the Origin header For requests w/o credentials (not sent by default), the server sets: Access-Control-Allow-Origin to * or same value as Origin For requests with credentials, the server should set: Access-Control-Allow-Origin to same value as Origin and Access-Control-Allow-Credentials to true JS automatically get access to response headers Cache-Control , Content-Language , Content-Type , Expires , Last-Modified or Pragma Additional headers should be listed by server in Access-Control-Expose-Headers header Safe request can be made with a <form> or a <script> , w/o any special methods CORS for safe requests If a request is cross-origin, the browser always adds the Origin header Origin: https://javascript.info for HTTP-request Access-Control-Allow-Origin: * for HTTP-response Response headers For cross-origin request, by default JS may access “safe” response headers Cache-Control , Content-Language , Content-Type , Expires , Last-Modified , Pragma There’s no Content-Length header in the list Additional permission is required to access that header to track the percentage of progress To grant JavaScript access to any other response header, the server must send the Access-Control-Expose-Headers header It contains a comma-separated list of unsafe header names that should be made accessible Bellow script is allowed to read the Content-Length and API-Key headers of the response
200 OK
Content-Type:text/html; charset=UTF-8
Content-Length: 12345
API-Key: 2c9de507f2c54aa1
Access-Control-Allow-Origin: https://javascript.info
Access-Control-Expose-Headers: Content-Length,API-Key
Unsafe requests for “unsafe” requests browser firstly sends “preflight” request, to ask for permission Preflight request occurs “behind the scenes”, it’s invisible to JavaScript JS only gets the response to the main request or an error if there’s no server permission A preflight request uses the method 'OPTIONS', no body and two headers: Access-Control-Request-Method method of the unsafe request Access-Control-Request-Headers provides a comma-separated list of its unsafe HTTP-headers If the server agrees to serve the requests, it should respond with empty body, status 200 and headers... Access-Control-Allow-Origin must be either * or the requesting origin to allow it Access-Control-Allow-Methods must have the allowed method Access-Control-Allow-Headers must have a list of allowed headers Access-Control-Max-Age header may specify a number of seconds to cache the permissions. So the browser won’t have to send a preflight for subsequent requests that satisfy given permissions. Take a look at step-by-step example https://javascript.info/fetch-crossorigin Credentials A cross-origin request from JavaScript by default does not bring credentials (cookies or HTTP authentication) but HTTP requests have them to include credentials in fetch and send cookies need to use credentials: "include" property option If the server agrees to accept the request with credentials, it should add... header Access-Control-Allow-Credentials: true to the response, in addition to Access-Control-Allow-Origin Access-Control-Allow-Origin is prohibited from using a star * for requests with credentials, must provide the exact origin there
fetch('http://another.com', { credentials: "include" })
Fetch page content
function FetchComponent() {
return (
<div>
<button onClick={fetchPage}>Fetch this page content and put into console</button>
</div>
)
}
async function fetchPage() {
const response = await fetch('/posts/fetch') // resolves with response headers
const result = await response.text()
console.log(result)
}