从 React 在 Express.js 服务器上运行 fetch() 时出现 Cors 错误

发布于 2025-01-09 14:04:53 字数 3793 浏览 0 评论 0原文

我有一个 Node.js Express.js REST API 服务器,使用在 localhost:4000 上运行的 cors 中间件。在 localhost:3000 上运行的 React 应用程序使用 fetch 向 Express 服务器发送 GET 请求并期望 JSON 响应。

但是,由于 CORS 错误,React 无法执行fetch

从源“http://localhost:3000”获取“http://localhost:4000/metrics”的访问已被 CORS 策略阻止:不存在“Access-Control-Allow-Origin”标头所请求的资源。如果不透明响应满足您的需求,请将请求模式设置为“no-cors”以在禁用 CORS 的情况下获取资源。

尽管在 API 服务器上使用了 cors 中间件,为什么仍然出现 CORS 错误?

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}`))

从 React 应用程序内部获取:

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);
}

常规:

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

响应标头:

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

请求标头:

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

还尝试了以下操作,但仍然收到 CORS 错误:

每次尝试后 Express 服务器都会重新启动

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()
})

运行 curl -v -H "Origin: http://localhost:3000" 的结果“http://localhost:4000/metrics”

标头:

*   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
< 

收到预期的 JSON 响应

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文