来自 Postman 和 Node 但不是 React 的 HTTP 请求

HTTP request working from Postman and Node but not React

Stack Overflow 上有几个与此类似的问题,none 提出的解决方案有效,所以我将详细介绍案例和我尝试过的方法。

我有一个托管在云 运行 上的服务器应用程序,只能使用请求授权 header 中的适当 Bearer 令牌访问。我已经尝试通过 Postman 和来自本地 Nodejs 服务器的 Axios 请求访问它,使用授权 header,它工作正常。使用 React(特别是 create-react-app),我收到以下错误:Access to XMLHttpRequest at 'https://myserver-lhp5a9xp5a-ue.a.run.app/api/rules' from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.

在服务器端,当传递了不正确的授权令牌时,我收到 Cloud 运行 给出的 403 错误。此外,当我允许来自云 运行 端的未经身份验证的访问时(因此不需要授权 header),请求工作正常,因此看起来这确实是授权 header 而不是 CORS。

此外,我在服务器端处理 CORS。这是我的 server-side 代码:

var express = require('express');
var router = express.Router();
const cors = require('cors');

router.options('/api/rules', cors());
router.get('/api/rules', cors(), (req, res, next) => {
  res.status(200).send()
});

这是我的 React 代码:

const axiosInstance = axios.create({
  baseURL: process.env.REACT_APP_API_BASE_URL
});

const buttonClickHandler = async (event) => {
  const resp = await axiosInstance.get('/api/rules'
   , {
     headers: {
       'Authorization': 'Bearer eyJhbGciOiJSUzI1NiIsImtpZ...' // I used this token within the same minute when trying the request via Postman or from my Nodejs app, so a token expiry isn't the issue.
     }
   }
  )
  console.log(resp.data)
}

这是我目前尝试的方法:

TLDR;

  • CORS 是一种内置于 Web 浏览器中的机制。这不是 UI 代码问题。
  • 要解决 CORS 问题,您需要在 API(服务器)端进行更改。

这是幕后工作:

浏览器:发送 OPTIONS 调用以检查服务器类型并在向 API 发送任何新请求之前获取 headers端点。它检查 Access-Control-Allow-Origin 的位置。考虑到这一点 Access-Control-Allow-Origin header 只是指定允许所有 CROSS ORIGINS,尽管默认情况下浏览器只允许相同的来源。

Postman:直接发送GETPOSTPUTDELETE等请求,不检查是什么类型服务器是并通过使用 OPTIONS 调用服务器来获取 header Access-Control-Allow-Origin

您必须在服务器中配置 Access-Control-Allow-Origin header 才能解决 CORS 问题。

经过一番挖掘,我找到了答案,感谢@aniket-kolekar 为我指明了正确的方向。

当 Postman 或 Nodejs 服务器查询 GETPOSTPUTDELETE 等端点时,它们会发送调用而不检查 OPTIONS 第一的。 Create-React-App 确实如此。

我查询的服务托管在云 运行 上,不允许未经身份验证的调用。因此,虽然我包含了进行 GET 调用的授权 header,但它并未包含在 pre-flight OPTIONS 调用中。事实上,CORS prevents auth headers from being included in an OPTIONS call.

A Cloud 运行 PM 在 this post 中回复说这是 Cloud 运行 的一个已知问题。我现在解决这个问题的方法是在 Cloud 运行 上托管两个服务——一个不需要身份验证,并且有效地充当代理服务器以将调用从客户端服务路由到受保护的服务器服务.