Understanding CORS: How Browsers and Servers Handle Cross‑Origin Requests

This article explains the CORS mechanism, detailing how browsers automatically add Origin headers, the difference between simple and non‑simple requests, the preflight exchange, required HTTP headers, and how servers respond to enable or reject cross‑origin communication.

Open Source Tech Hub
Open Source Tech Hub
Open Source Tech Hub
Understanding CORS: How Browsers and Servers Handle Cross‑Origin Requests

Introduction

CORS (Cross‑Origin Resource Sharing) requires support from both browsers and servers; all modern browsers support it, with IE needing version 10 or higher. The entire CORS communication is performed automatically by the browser, so developers write the same AJAX code as for same‑origin requests.

How CORS Works

The specification defines new HTTP headers that browsers must send when they have permission to access remote URLs. While servers perform validation, the browser is responsible for adding these headers and applying related restrictions.

For data‑modifying Ajax or HTTP methods (anything other than GET, or POST with certain MIME types), the browser must first issue an OPTIONS preflight request to determine whether the server permits the cross‑origin request and whether credentials such as cookies may be included.

Two Types of Requests

1. Simple Request

A request is considered simple if it meets two conditions:

The HTTP method is HEAD, GET or POST.

Only the following request headers are used: Accept, Accept-Language, Content-Language, Last-Event-ID, and Content-Type limited to application/x-www-form-urlencoded, multipart/form-data, or text/plain.

For a simple request the browser adds an Origin header to the request.

GET /cors HTTP/1.1
Origin: http://api.tinywan.com
Host: api.alice.com
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...

The Origin header tells the server the request’s source (scheme + host + port) so the server can decide whether to allow it.

2. Non‑Simple Request (Preflight)

Requests that use methods such as PUT or DELETE, or a Content-Type like application/json, trigger a preflight request.

Non‑simple CORS requests add an extra HTTP query called a "preflight" request before the actual request.

The browser first asks the server whether the origin, method, and custom headers are permitted.

var url = 'http://api.alice.com/cors';
var xhr = new XMLHttpRequest();
xhr.open('PUT', url, true);
xhr.setRequestHeader('X-Custom-Header', 'value');
xhr.send();

The browser then sends an OPTIONS request:

OPTIONS /cors HTTP/1.1
Origin: http://api.tinywan.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: X-Custom-Header
Host: api.alice.com
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...
The preflight request uses the OPTIONS method; the key headers are Origin , Access-Control-Request-Method , and Access-Control-Request-Headers .

Access-Control-Request-Method lists the HTTP method the actual request will use (e.g., PUT).

Access-Control-Request-Headers is a comma‑separated list of any custom headers the actual request will send (e.g., X-Custom-Header).

Preflight request example
Preflight request example

Preflight Response

If the server approves the request, it responds with the appropriate CORS headers:

HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 01:15:39 GMT
Server: Apache/2.0.61 (Unix)
Access-Control-Allow-Origin: http://api.tinywan.com
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: X-Custom-Header
Access-Control-Allow-Credentials: true
Access-Control-Max-Age: 1728000
Content-Type: text/html; charset=utf-8
Content-Encoding: gzip
Content-Length: 0
Connection: Keep-Alive

The crucial header Access-Control-Allow-Origin indicates which origin may access the resource; it can also be set to * to allow any origin. Access-Control-Allow-Origin: * If the server denies the preflight, it returns a normal HTTP response without CORS headers, causing the browser to fire an error captured by the XMLHttpRequest onerror callback.

XMLHttpRequest cannot load http://api.tinywan2.com.
Origin http://api.bob.com is not allowed by Access-Control-Allow-Origin.

Other important response headers include:

Access-Control-Allow-Methods : comma‑separated list of methods the server supports.

Access-Control-Allow-Headers : list of headers the server permits.

Access-Control-Allow-Credentials : indicates whether credentials may be included.

Access-Control-Max-Age : optional cache duration (in seconds) for the preflight result; the example shows 20 days (1728000 s).

Preflight response example
Preflight response example

Normal Request After Preflight

Once the preflight succeeds, subsequent CORS requests behave like simple requests, always containing an Origin header, and the server always includes Access-Control-Allow-Origin in its response.

PUT /cors HTTP/1.1
Origin: http://api.tinywan.com
Host: api.alice.com
X-Custom-Header: value
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...

Server response example:

Access-Control-Allow-Origin: http://api.tinywan.com
Content-Type: text/html; charset=utf-8
Normal CORS request example
Normal CORS request example
Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

frontendCORSCross-Originhttp-headersWeb Securitypreflight
Open Source Tech Hub
Written by

Open Source Tech Hub

Sharing cutting-edge internet technologies and practical AI resources.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.