Observe a CORS preflight
Run a simple GET and a preflighted POST, then inspect the final response shared with JavaScript.
Prediction
Without matching cached preflight permission, adding the fixed non-safelisted request field makes the browser send OPTIONS before the intended request.
Controlled observation
Compare the fixed simple GET with the POST that carries one non-safelisted field. The result panel shows only the final Fetch response. Use browser developer tools to inspect the automatically generated OPTIONS exchange separately.
Run the POST first in a fresh browser context, then repeat it with the network
log preserved. This Lab advertises Access-Control-Max-Age: 600, allowing
preflight permission to be cached for up to 600 seconds. Browsers may impose a
shorter limit or evict the permission earlier. A repeat run may show only POST
because the browser reuses a matching cached grant.
To observe a fresh preflight again, use a new isolated browser context, such as a separate browser profile. Reloading the page does not guarantee a new OPTIONS exchange.
Explanation
Preflight asks whether an origin may use the intended method and fields. A successful HTTP response still needs compatible CORS sharing fields. Preflight permissions have their own cache; seeing no new OPTIONS on a repeat request does not mean the non-safelisted field stopped requiring permission.
Controlled exercise
Run this observation
Compare the final Fetch results for the simple GET and preflighted POST; inspect developer tools to see OPTIONS separately.
Interactive controls require JavaScript. The static response and portable examples remain available below.
Ready. No request has run.
Controlled request
- Method
- GET
- URL
https://lab.httpclarity.com/v1/cors-preflight/simple- Permitted headers
- None
- Body
- None
Browser-observed response
No live response yet. The representative static example remains useful without JavaScript or the Worker.
Static response example
HTTP/1.1 200 OK
Content-Type: application/json
X-Lab-Scenario: cors-simple
{"fixture":"simple","scenario":"cors-preflight"}Timing is browser elapsed time. Fetch hides Set-Cookie, raw wire bytes, reliable compressed size, and some redirect details.
Portable examples
'curl' '--include' '--request' 'GET' 'https://lab.httpclarity.com/v1/cors-preflight/simple'Scroll horizontally to read any long lines.const response = await fetch("https://lab.httpclarity.com/v1/cors-preflight/simple", {
"method": "GET"
});
console.log(response.status, await response.text());Scroll horizontally to read any long lines.<?php
$options = ['http' => [
'method' => 'GET',
'ignore_errors' => true,
]];
$context = stream_context_create($options);
$body = file_get_contents('https://lab.httpclarity.com/v1/cors-preflight/simple', false, $context);
var_dump($http_response_header, $body);Scroll horizontally to read any long lines.Need a full API client? Copy the generated cURL command, then import it in Hoppscotch. HTTPClarity sends no request data to Hoppscotch.
Continue in Hoppscotch (opens in a new tab)