You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Ngrok与Express服务器的CORS错误排查:‘No Access-Control-Allow-Origin’头缺失及网络错误问题

Ngrok与Express服务器的CORS错误排查:‘No Access-Control-Allow-Origin’头缺失及网络错误问题

问题场景

我正在开发一个使用Firebase Authentication实现Google登录的React应用。登录成功后,我获取Firebase ID令牌并发送到Node.js/Express服务器进行验证。

但当我尝试Google登录时,浏览器控制台出现以下错误:

Access to XMLHttpRequest at 'http://localhost:3005/api/verify-token' from origin 'https://e7e7-43-252-15-140.ngrok-free.app' 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.

SignUp.jsx:39 Error during sign-in: AxiosError {message: 'Network Error', name: 'AxiosError', code: 'ERR_NETWORK', config: {…}, request: XMLHttpRequest, …}

POST http://localhost:3005/api/verify-token net::ERR_FAILED

我的React应用通过ngrok运行在https://e7e7-43-252-15-140.ngrok-free.app,Express服务器运行在http://localhost:3005

我已经尝试过的方法:

  • 给Express服务器添加了cors中间件,并指定ngrok URL为允许的源
  • 验证了服务器上Firebase Admin SDK已正确初始化
  • 确认React应用已发送Authorization请求头
  • 检查了服务器端的令牌验证逻辑

我的问题:
为什么仍然会出现CORS错误和网络错误?是我的CORS配置有问题,还是有其他被忽略的问题?如何正确配置Express服务器以允许来自ngrok URL的跨域请求?


排查与解决方案

看起来你遇到的是典型的跨域请求配置细节问题,虽然你已经加了CORS中间件,但可能是配置顺序、环境差异或者规则覆盖导致的,我来帮你一步步梳理:

1. 检查CORS中间件的挂载顺序与配置细节

首先要确保CORS中间件是在所有路由之前挂载的,否则你的/api/verify-token路由可能不会应用CORS规则。另外,针对你的HTTPS ngrok源和HTTP本地服务器的场景,配置要更明确:

const cors = require('cors');
const express = require('express');
const app = express();

// 明确指定允许的ngrok源
const allowedOrigin = 'https://e7e7-43-252-15-140.ngrok-free.app';

// 先挂载CORS中间件,再挂载路由
app.use(cors({
  origin: allowedOrigin,
  credentials: true, // 如果你请求带了认证头/Cookie,必须开启这个
  allowedHeaders: ['Authorization', 'Content-Type'], // 明确允许你发送的Authorization头
  methods: ['GET', 'POST', 'OPTIONS'] // 包含预检请求的OPTIONS方法
}));

// 之后再挂载你的路由
app.post('/api/verify-token', (req, res) => {
  // 你的令牌验证逻辑
});

2. 解决HTTPS与HTTP的混合内容限制

你的React应用是HTTPS协议,而Express服务器是HTTP,浏览器的混合内容安全策略可能会悄悄阻止请求(虽然控制台报错是CORS,但有时候混合内容会触发类似的网络错误)。可以临时用以下方法测试:

  • 在Chrome地址栏输入chrome://flags/#allow-insecure-localhost,启用该选项后重启浏览器,允许本地HTTPS请求调用HTTP接口
  • 或者给Express服务器配置自签名HTTPS证书,让服务器也用HTTPS协议运行(适合长期测试)

3. 验证CORS中间件是否真的生效

用curl发送一个OPTIONS预检请求,检查服务器响应头是否包含Access-Control-Allow-Origin

curl -X OPTIONS -H "Origin: https://e7e7-43-252-15-140.ngrok-free.app" http://localhost:3005/api/verify-token -v

如果响应头里没有这个字段,说明你的CORS中间件没有正确生效,可能是代码顺序错了,或者某个路由/中间件覆盖了响应头。

4. 检查Axios的请求配置

确保Axios请求没有额外的配置问题,比如是否正确设置了请求头:

import axios from 'axios';

const verifyToken = async (idToken) => {
  try {
    const response = await axios.post(
      'http://localhost:3005/api/verify-token',
      {}, // 如果需要传请求体可以在这里加
      {
        headers: {
          'Authorization': `Bearer ${idToken}`,
          'Content-Type': 'application/json'
        },
        withCredentials: true // 如果CORS开启了credentials,这里也要对应开启
      }
    );
    return response.data;
  } catch (err) {
    console.error('Error during sign-in:', err);
  }
};

5. 排查本地网络拦截问题

有时候本地防火墙、杀毒软件或者代理工具(比如Charles、Fiddler)会拦截本地HTTP请求,导致ERR_FAILED错误。可以先关闭这些工具,或者直接在浏览器访问http://localhost:3005/api/verify-token(即使返回405 Method Not Allowed,只要能收到响应就说明服务器是通的)。

6. 动态适配ngrok的可变URL(可选)

如果你经常更换ngrok的临时URL,可以用动态验证的方式,不用每次修改配置:

app.use(cors({
  origin: (origin, callback) => {
    // 允许本地开发环境(无origin的情况)和所有ngrok免费域名
    if (!origin || origin.includes('ngrok-free.app')) {
      callback(null, true);
    } else {
      callback(new Error('Not allowed by CORS'));
    }
  },
  credentials: true,
  allowedHeaders: ['Authorization', 'Content-Type']
}));

调整完配置后,重启Express服务器再测试,应该就能解决问题了。如果还是有疑问,可以把你的CORS配置代码贴出来,我再帮你细化排查。


备注:内容来源于stack exchange,提问作者Mufees Mhd

火山引擎 最新活动