2

I have a Node.js Express.js REST API server using the cors middleware running on localhost:4000. A React app running on localhost:3000 uses fetch to send a GET request to the Express server and expects a JSON response.

However, React is unable to perform the fetch due to a CORS error.

Access to fetch at 'http://localhost:4000/metrics' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

Why is it still getting a CORS error despite using the cors middleware on the API server?

api_server.js:

import { selectMetrics } from './db'
import express from 'express'
import cors from 'cors'

const PORT = 4000

const app = express()
const corsOptions = {
  origin: '*',
  credentials: true, //access-control-allow-credentials:true
  optionSuccessStatus: 200,
}
app.use(cors(corsOptions))
app.set('json spaces', 2)

app.get('/metrics', async (req, res) => {
  const metrics = await selectMetrics()
  return res.json(metrics)
})

app.listen(PORT, () => console.log(`API server listening on port ${PORT}`))

Fetch from inside the React app:

async () => {
  const apiUrl = "http://localhost:4000/metrics";
  const response = await fetch(apiUrl);
  if (!response.ok) {
    throw new Error("Error fetching from /metrics");
  }

  console.log("/metrics response:", response);
}

General:

Request URL: http://localhost:4000/metrics
Request Method: GET
Status Code: 200 
Referrer Policy: strict-origin-when-cross-origin

Response Headers:

Content-Length: 30008
Content-Type: application/json; charset=utf-8
Date: Thu, 24 Feb 2022 05:12:01 GMT
ETag: W/"7538-9fQpPD2E0HULEM9eRjgd2o2OHGo"
X-Powered-By: Express

Request Headers:

Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Connection: keep-alive
Host: localhost:4000
If-None-Match: W/"7538-9fQpPD2E0HULEM9eRjgd2o2OHGo"
Origin: http://localhost:3000
Referer: http://localhost:3000/
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-site
Sec-GPC: 1
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36

Also tried the following, but still getting CORS error:

Express server restarted after each try

const app = express()
app.use(cors())
const app = express()
const corsOptions = {
  origin: '*',
  optionSuccessStatus: 200,
}
app.use(cors(corsOptions))
const app = express()
app.use(cors())
app.options('*', cors())
const app = express()
app.use(function (req, res, next) {
  res.header('Access-Control-Allow-Origin', 'http://localhost:4000')
  res.header('Access-Control-Allow-Credentials', true)
  res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS')
  res.header(
    'Access-Control-Allow-Headers',
    'Origin,X-Requested-With,Content-Type,Accept,content-type,application/json',
  )
  next()
})

Result of running curl -v -H "Origin: http://localhost:3000" "http://localhost:4000/metrics":

Headers:

*   Trying 127.0.0.1:4000...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 4000 (#0)
> GET /metrics HTTP/1.1
> Host: localhost:4000
> User-Agent: curl/7.68.0
> Accept: */*
> Origin: http://localhost:3000
> 
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< X-Powered-By: Express
< Content-Type: application/json; charset=utf-8
< Content-Length: 30008
< ETag: W/"7538-9fQpPD2E0HULEM9eRjgd2o2OHGo"
< Date: Thu, 24 Feb 2022 05:44:21 GMT
< Connection: keep-alive
< Keep-Alive: timeout=5
< 

Expected JSON response is received

Athena Wisdom
  • 6,101
  • 9
  • 36
  • 60
  • You can't use `credentials` with `*` origins. Do you even need credential (aka cookie) support? – Phil Feb 24 '22 at 05:22
  • Regarding your last edit.... whatever you do, don't write your own CORS middleware. The `cors` package handles everything already and better – Phil Feb 24 '22 at 05:45
  • @PHil updated question with the output of the `curl` command. Response looks good – Athena Wisdom Feb 24 '22 at 05:47
  • Well no, it's missing the `Access-Control-Allow-Origin` response header. Are you absolutely sure you've **saved changes** to your `api_server.js` file and are restarting Express each time? What command are you using to start the server? – Phil Feb 24 '22 at 05:49
  • 1
    @Phil Thats it! I'm using a yarn script to start the server, but did not do a webpack rebuild. It works now after running a `webpack --mode development`. Thanks! – Athena Wisdom Feb 24 '22 at 05:53
  • Webpack is for your frontend, shouldn't have anything to do with you server – Phil Feb 24 '22 at 05:54
  • Server is using webpack and babel to access some features like `import` – Athena Wisdom Feb 24 '22 at 05:54

0 Answers0