Cross-Origin HTTP Requests
Cross-Origin Request with Preflight
A more complex CORS scenario necessitates a preliminary HTTP message exchange: such "preflight negotiation" is required for the client and the server to agree upon the set of allowed methods and headers.
In the code below, the client script not only tries to retrieve a resource from an extraneous domain, but also appends custom headers to the HTTP request:
  var xhr = new XMLHttpRequest();  
 xhr.onload = loadEvent => {
  console.log(loadEvent.target.responseText);
  console.log(loadEvent.target.getAllResponseHeaders());
 };
 xhr.open('GET', 'http://example.net/cross-origin-request-handler.php'); 
 xhr.responseType = 'text';
 xhr.setRequestHeader('X-Header-1', 'Value 1');
 xhr.setRequestHeader('X-Header-2', 'Value 2');
 xhr.send(); 
The browser does not send the GET request directly: first it ascertains the server's consent to accept custom headers of the cross-origin request. To perform the "lookup", the browser creates a preflight request with the OPTIONS method and provides it with two special headers - Access-Control-Request-Method and Access-Control-Request-Headers:
  request line 
 OPTIONS http://example.net/cross-origin-request-handler.php HTTP/1.1 
 request headers
 Origin: http://example.com
 Access-Control-Request-Method: GET
 Access-Control-Request-Headers: x-header-1, x-header-2 
The Access-Control-Request-Method indicates the HTTP method which the upcoming CORS request is going to use. Access-Control-Request-Headers is a list of comma-separated headers of the request.
If the server agrees to handle future CORS requests with the specified method and custom headers, it can respond to the preflight lookup in this way:
  <?php 
  header('Access-Control-Allow-Origin: *');
  header('Access-Control-Allow-Methods: GET');
  header('Access-Control-Allow-Headers: x-header-1, x-header-2');
 ?> 
In addition to Access-Control-Allow-Methods and Access-Control-Allow-Headers, the server can include the Access-Control-Max-Age in its response. The header will tell the browser to abide by the result of the current preflight negotiation for a specified number of seconds:
  header('Access-Control-Max-Age: 600');  
 Another hint for the browser is the Access-Control-Allow-Credentials header. Its true value gives permission to the use of forthcoming CORS requests with user credentials: 
  header('Access-Control-Allow-Credentials: true');  
After the browser parses the server response to the preflight request, it generates a real GET request with custom headers created in the client code. The CORS message contains the Origin header, anyway:
  request line 
 GET http://example.net/cross-origin-request-handler.php HTTP/1.1
 request headers
 Origin: http://example.com
 X-Header-1: Value 1
 X-Header-2: Value 2 
The server must include Access-Control-Allow-Origin in its response. In addition, it can enumerate response headers that will be available to the client script:
  <?php 
  header('Access-Control-Allow-Origin: *');
  header('Access-Control-Expose-Headers: date, server, transfer-encoding'); 
  header('Content-Type: text/plain; charset=UTF-8');
  echo 'This is just a demo';
 ?> 
 If the browser does not detect the Access-Control-Expose-Headers in the server response, it only exposes the Content-Type header to the script. An attempt to get the value of some other header will return null. 
For illustration, the server-side code below handles both preflight OPTIONS and cross-origin GET requests in a single block of code:
  <?php 
  if($_SERVER['REQUEST_METHOD'] == 'OPTIONS') { // handling preflight request
   header('Access-Control-Allow-Origin: *');
   header('Access-Control-Allow-Methods: GET'); 
   header('Access-Control-Allow-Headers: x-header-1, x-header-2');
   header('Access-Control-Max-Age: 600'); 
  } else { // handling CORS requests
   header('Access-Control-Allow-Origin: *'); 
   header('Access-Control-Expose-Headers: date, server, transfer-encoding');
   header('Content-Type: text/plain; charset=UTF-8');
   echo 'This is just a demo';
  }
 ?> 
CORS and Fetch API
The same principles of cross-origin requests handling are applied to routines based on the Fetch API:
  var request = new Request('http://example.net/cross-origin-request-handler.php', { 
  method: 'GET',
  headers: {
   'X-Header-1': 'Value 1',
   'X-Header-2': 'Value 2'
  },
  mode: 'cors'
 }
 );
 fetch(request).then(response => {
  console.log(response.headers.get('Connection')); // null
  console.log(response.headers.get('Date')); // a valid value
  response.text().then(txt => {
   console.log(txt);
  });
 }, eObj => {
  console.error(eObj);
 }
 );