【问题标题】:Express CORS hell快递 CORS 地狱
【发布时间】:2022-02-08 17:39:17
【问题描述】:

我在使用一个非常简单的应用时遇到了 CORS 问题,我花了大约 10 分钟来编写它,并且我花了几个小时试图修复这个 CORS 错误。

用 React 编写的前端使用 axios 向 Express 后端发出 POST 请求。

app.use(cors()) 在我的 Express 应用中的单个路由之前调用。

这是我的 React 应用程序中的 axios 请求:

(await axios.post("http://localhost:3000/login", {username: username, password: password})).data.success

我收到了这个 CORS 错误:

Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at...

OPTIONS 请求的标头

POST 请求的标头

不过,localhost 上一切正常。

快递代码:

require('dotenv').config();
const createError       = require('http-errors');
const express           = require('express');
const cors              = require('cors');
const compression       = require('compression');
const app               = express();

app.use(cors({origin: "*", allowedHeaders: ['Content-Type']}));
app.use(express.json());
app.use(compression());
app.use(express.urlencoded({extended: true}));
app.post("/login", (req, res) => {
    const params = req.body;
    if (params.username === process.env.USERNAME && params.password === process.env.PASSWORD)
        return res.json({success: true});
    else
        return res.status(401).json({success: false});
});

app.use((req, res, next) => next(createError(404)));
app.listen(process.env.NODE_PORT, () => console.log("Listening on port " + process.env.NODE_PORT));

当前的、不理想的可行解决方案:

使用机器的 IP 而不是localhost

(await axios.post("http://192.168.*.*:3000/login", {username: username, password: password})).data.success 

【问题讨论】:

  • 能不能给个快递码
  • 刚刚在@SeanLawton的问题中添加了
  • 您可以排除本地域或仅使用this extension 进行开发。
  • 如何排除本地域? @mamady
  • @Alexandre This 应该会有所帮助。

标签: javascript reactjs express cors


【解决方案1】:

问题

the Axios source code 可以看出,当post 的第二个参数是一个对象时(这里就是这种情况),Axios 将请求的Content-Type 标头设置为application/json

This header value is such as to cause the browser to trigger CORS preflight。然后,服务器必须在预检请求响应的Access-Control-Allow-Headers 标头中显式列出Content-Type;否则,CORS 预检将失败,导致浏览器出现 CORS 错误。

请注意,Express CORS 中间件(您当前所依赖的)的 default configuration 不允许任何标头。

解决方案

在您的 CORS 配置中明确允许 Content-Type。您可以使用CORS middleware's configuration objectallowedHeaders 属性来做到这一点。

【讨论】:

  • 我已经尝试过了,但它不起作用。仍然得到与使用 localhost 之前相同的 CORS 错误。 app.use(cors({origin: "*", allowedHeaders: ['Content-Type']}));
  • @Alexandre 好的,但至少,您确实需要允许 Content-Type 标头;这很清楚。要向我们提供更多信息,请编辑您的问题并从浏览器的网络选项卡添加预检请求和响应的屏幕截图。还要从浏览器的“控制台”选项卡中添加 CORS 错误的屏幕截图。
  • 我上传了 CORS 错误的屏幕截图并按照建议更新了当前应用配置。
  • @Alexandre 您的屏幕截图显示了预检和实际请求,但没有显示响应。我们两者都需要。
  • 这两个请求都没有任何响应:Response body is not available to scripts (Reason: CORS Failed)。 @jub0bs
【解决方案2】:

您需要配置您的 cors 选项。源可以是一个字符串或数组,它是允许发出请求的源的白名单。如果你需要它是动态的,你甚至可以用一个函数来处理它。您还可以允许或禁止方法、验证凭据等。检查package readme

Cors 是一种安全机制,用于阻止不同域之间的任何尝试。例如,您的后端位于以下域中:https://wordpress.com 并且您想从您的域中获取您的前端 https://example.com 这可以防止任何人都可以访问您的端点以窃取信息,但这不应该是您唯一的安全机制

const corsOptions = {
    origin: "http://localhost:3000",
    methods: ["GET","POST"]
};

app.use(cors(corsOptions));

【讨论】:

  • 不,不是这样,cors() 默认为{origin: "*"} 并在未传递任何选项时处理预检请求
【解决方案3】:

使用机器IP代替localhost

await axios.post("http://192.168.*.*:3000/login", {username: username, password: password})).data.success` 

【讨论】:

  • 为什么会有帮助?如果与发送请求的页面不同的域/端口/协议,则 IP 与域仍然是不同的来源。
  • @KevinB 确实会。但该错误实际上并不是 CORS 配置错误(至少,我不这么认为)。前面正在使用 localhost 调用后面。因此,浏览器在每个请求上都会引发 CORS 错误。将 localhost 更改为服务器的 IP 解决了这个问题。您可能已经注意到,我没有使用 CORS 的经验,因此我无法解释这有何帮助。
  • 我明白了,听起来当时发生的事情是通过使用 IP,您完全绕过了 cors,使其没有必要。
  • @KevinB 我不认为我通过使用 IP 使 cors 变得不必要。如果没有必要,可以删除 Express 应用程序中的 cors 配置而不会引发 cors 错误,但在删除 cors 配置后我仍然会收到 cors 错误:XMLHttpRequest cannot load http://192.168.1.34:3000/login due to access control checks.
  • 我同意,我认为你是对的,这是与 CORS 无关的某种形式的错误配置。
猜你喜欢
  • 1970-01-01
  • 2014-12-01
  • 2018-03-01
  • 2017-10-10
  • 1970-01-01
  • 2017-09-19
  • 2016-07-23
  • 2016-05-29
  • 1970-01-01
相关资源
最近更新 更多