为避免 'Access-Control-Allow-Origin' 问题,应如何在调用位于其他地方的 API 的 MERN 应用程序上设置 CORS?

To avoid the 'Access-Control-Allow-Origin' issue, how should CORS be set up on a MERN app that calls an API that is located somewhere else?

我正在玩一个调用 themealdb api 的 MERN 应用程序,它工作正常,直到应用 JWT 和 cookie 的身份验证和授权。如果我登录,那么无论何时拨打电话,我都会收到以下内容

Access to XMLHttpRequest at 'https://www.themealdb.com/api/json/v1/1/search.php?f=a' from origin 'http://localhost:3000' has been blocked by CORS policy: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.

在我看来,React 端的以下代码行是罪魁祸首

axios.defaults.withCredentials = true;

如果我注释掉这一行,问题就会消失,调用也没有问题。

环顾四周的答案似乎可以在对我来说是 Express 的后端制定解决方案,但到目前为止没有任何效果。 Express 代码有这个用于 cors:

app.use(cors({origin: ['http://localhost:3000'], credentials: true}));

我用 corsOptions 的 let 和 var 将其替换为以下内容,以防出现相同的错误:

let corsOptions = {
    origin: 'http://localhost:3000',
    credentials : true
   }
  
  app.use(cors(corsOptions));
  
  app.use(function (req, res, next) {   
      res.setHeader('Access-Control-Allow-Origin', 'http://localhost:3000');    
      res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');    
      res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type');   
      res.setHeader('Access-Control-Allow-Credentials', true);    
      next();
  });

有什么建议吗?对于这种情况,需要在服务器端添加什么才能使其正常工作?

谢谢

我通常使用此代码段为预配置的来源列表启用 CORS:

const allowOrigins = ['http://localhost:3000', /** other domains if any */ ]
const corsOptions = {
  credentials: true,
  origin: function(origin, callback) {
    if (allowOrigins.indexOf(origin) !== -1) {
      callback(null, true)
    } else {
      callback(new Error('Not allowed by CORS'))
    }
  }
}

server.use(cors(corsOptions));

此外,as per MDN, you can try setting the withCredentials 选项 false 在您的客户端上。

或者,如果您要连接到您不维护的服务,您可以创建一个 Node 代理来调用第三方服务,而不是您的客户端直接调用它。

const express = require('express')
const request = require('request')
const port = process.env.PORT || 8000

let server = express()

const proxyMiddleware = (req, res, next) => {
  let url = `https://www.example.com/${req.url}`
  let proxyRequest = request(url)

  // Pass request to proxied request url
  req.pipe(proxyRequest)

  // Respond to the original request with the response from proxyRequest
  proxyRequest.pipe(res)
}

server.use(proxyMiddleware)

server.listen(port, () => console.log(`Listening on ${port}`))