Skip to content

/flags/cors/http-server-cors

http-server --cors: serve local files with Access-Control-Allow-Origin

verified onenvironmentlocal · windows 10.0.26200 arm64 · GNU bash 5.3.15 (Git Bash)updated
tool
CORS
command
http-server
flag
--cors[=HEADERS]
default
off (no CORS headers; cross-origin fetch() from a page on another port or host is blocked)

npx http-server ./dist --cors makes the Node.js static file server add Access-Control-Allow-Origin: * and a fixed Access-Control-Allow-Headers list to every response, so a web app on another origin (for example a dev server on localhost:3000) can fetch() the files. --cors=Authorization,X-Api-Version appends extra request headers to that list. Without the option http-server sends no CORS headers and the browser blocks cross-origin reads with No 'Access-Control-Allow-Origin' header.

Headers with and without --cors

Three local servers on the same folder: no option, --cors, and --cors with extra headers. A cross-origin GET and a preflight are sent to each:

bash
npm init -y >/dev/null && npm install --silent --no-audit --no-fund http-server@14.1.1 >/dev/null 2>&1
mkdir site && echo '{"ok":true}' > site/data.json
timeout 15 node node_modules/http-server/bin/http-server site -p 5416 -a 127.0.0.1 -s &
timeout 15 node node_modules/http-server/bin/http-server site -p 5417 -a 127.0.0.1 -s --cors &
timeout 15 node node_modules/http-server/bin/http-server site -p 5419 -a 127.0.0.1 -s --cors=Authorization,X-Api-Version &
sleep 4
for port in 5416 5417 5419; do
  echo "--- port $port, GET:"
  curl -s -D - -o /dev/null -H "Origin: http://localhost:3000" http://127.0.0.1:$port/data.json | tr -d '\r' | grep -iE "^HTTP|^access-control"
done
echo "--- port 5419, preflight for PUT with Authorization:"
curl -s -D - -o /dev/null -X OPTIONS -H "Origin: http://localhost:3000" -H "Access-Control-Request-Method: PUT" \
  -H "Access-Control-Request-Headers: Authorization" http://127.0.0.1:5419/data.json | tr -d '\r' | grep -iE "^HTTP|^access-control"
wait

Output

--- port 5416, GET:
HTTP/1.1 200 OK
--- port 5417, GET:
HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept, Range
--- port 5419, GET:
HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept, Range, Authorization, X-Api-Version
--- port 5419, preflight for PUT with Authorization:
HTTP/1.1 204 No Content
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept, Range, Authorization, X-Api-Version

Without the option there are no Access-Control-* headers at all. With it the origin is always *, whatever the request's Origin was, and preflight requests get 204 No Content.

What --cors sends and what it does not

HeaderValue with --corsConsequence in the browser
Access-Control-Allow-Origin*Any origin may read responses that are fetched without credentials
Access-Control-Allow-HeadersOrigin, X-Requested-With, Content-Type, Accept, Range (+ the list after =)Requests with other headers, such as Authorization, fail the preflight
Access-Control-Allow-Methodsnot sentOnly CORS-safelisted methods (GET, HEAD, POST) pass a preflight
Access-Control-Allow-Credentialsnot sentfetch with credentials: 'include' is blocked
Access-Control-Max-Agenot sentBrowsers cache the preflight only briefly

The missing Allow-Methods rarely matters for a static server, which answers only GET and HEAD anyway (PUT gets 405). The header list matters more: a request that sends Authorization is rejected with Request header field is not allowed by Access-Control-Allow-Headers unless the header is added with --cors=Authorization.

Pitfalls

  • Wildcard and credentials. Because the origin is *, cookies and HTTP authentication cannot be used cross-origin; see wildcard origin with credentials. Use a server that reflects the origin, such as live-server --cors, when you need them.
  • Caching. http-server sends cache-control: max-age=3600 by default. When you toggle --cors and reload, the browser may reuse a cached response without the headers; add -c-1 to disable caching while testing.
  • Production. --cors is meant for local development and test fixtures. Public APIs should list allowed origins explicitly instead of * when responses are not meant for everyone.

To check headers the way a browser does, use test CORS with curl or the explanation of the preflight request.

FAQ

Why do I still get a CORS error with http-server --cors?

Check which request fails. --cors allows any origin but only a fixed list of request headers and sends no Access-Control-Allow-Methods. A request with Authorization or a custom header needs --cors=Authorization, and PUT or DELETE are not allowed at all.

Does http-server --cors allow cookies?

No. It sends Access-Control-Allow-Origin: * and no Access-Control-Allow-Credentials, so fetch with credentials: 'include' is blocked. Wildcard origins and credentials cannot be combined anyway.

Do I need --cors when the page and the files come from the same http-server?

No. CORS only applies to cross-origin requests. A page on http://127.0.0.1:8080 that fetches /data.json from the same host and port needs no CORS headers.

Sources