What Is a Simple Request and When Does the Browser Send a Preflight Request?
In the previous article, we learned that browsers sometimes send an OPTIONS request before the actual Cross-Origin request. This process is known as a CORS Preflight Request. But does this happen for every request? The answer is no. Browsers only perform a Preflight Request when the request does not qualify as a Simple Request.
What Is a Simple Request?
A Simple Request is a Cross-Origin request that satisfies a specific set of conditions defined by the Fetch specification. Since these requests are considered low risk, the browser sends them directly without performing a Preflight check. CORS rules still apply to the response, but no preliminary OPTIONS request is needed.
Requirements for a Simple Request
A request is considered simple only if all of the following conditions are met.
1. HTTP Method
The request method must be one of:
- GET
- HEAD
- POST
Methods such as PUT, PATCH, and DELETE automatically trigger a Preflight Request.
2. Request Headers
The request may only include CORS-safelisted request headers, such as:
AcceptAccept-LanguageContent-Language
Adding headers like Authorization: Bearer <token> or X-API-Key: 123456 causes the browser to perform a Preflight Request.
3. Content-Type
If the request has a body, its Content-Type must be one of:
application/x-www-form-urlencodedmultipart/form-datatext/plain
Using a content type such as application/json makes the request non-simple and triggers a Preflight Request. This is one of the most common reasons developers see OPTIONS requests in modern web applications.
Examples
This request is simple:
fetch("/users")
No Preflight Request is sent.
This request is also simple:
fetch("/login", {
method: "POST",
headers: { "Content-Type": "text/plain" }
})
Again, no Preflight is required.
However, this request is not simple:
fetch("/login", {
method: "POST",
headers: { "Content-Type": "application/json" }
})
The browser first sends an OPTIONS request.
The same happens here:
fetch("/profile", {
headers: { "Authorization": "Bearer token" }
})
Because the Authorization header is not CORS-safelisted, a Preflight Request is required.
Summary
A browser sends a Preflight Request only when a Cross-Origin request does not meet the requirements of a Simple Request. The most common triggers are:
- Using methods such as
PUT,PATCH, orDELETE - Including non-safelisted headers such as
Authorization - Using content types like
application/json
This is why seeing an OPTIONS request before the actual request is completely normal in many modern APIs.
Comments
No comments yet. Start the discussion.