cors 子域失败

Posted

技术标签:

【中文标题】cors 子域失败【英文标题】:cors failing for subdomains 【发布时间】:2019-09-07 18:30:18 【问题描述】:

CORS 在域和子域中无法正常工作。 我有一个托管在 https://api.example.com 的 NodeJS 服务器 我有两个 ReactJS 客户端

客户端 1。https://example.com

客户端 2。https://subdomain.example.com

我已将客户端 1 配置为强制使用 www,以便客户端 1 使用单一来源。 当我打开 Clien1 时,它工作正常。 当我打开 Client2 时,出现

从源“https://subdomain.example.com”访问“https://api.example.com/someAPI”处的 XMLHttpRequest 已被 CORS 策略阻止:“Access-Control-Allow-Origin”标头的值“https://www.example.com”不等于提供的来源

当我按 Ctrl+F5 时它工作正常,但之后如果我刷新 Client1 则错误出现在 Client1 上

从源“https://www.example.com”访问“https://api.example.com/someAPI”处的 XMLHttpRequest 已被 CORS 策略阻止:“Access-Control-Allow-Origin”标头的值“https://subdomain.example.com”不等于提供的来源。

现在,当我在 Client1 上按 Ctrl+F5 时,它工作正常,但同样的错误出现在 Client2 上。

我的nodeJS服务器配置如下

var whitelist = ['https://www.example.com', 'https://subdomain.example.com'];
    getCorsCoptions(req, callback) 
    var getOriginValue = () => 
      if (whitelist.indexOf(req.header('origin')) !== -1) 
        return true;
       else 
        log.error(__filename, 'Not allowed by CORS', origin);
        return false;
      
    
    var corsOptions = 
      origin: getOriginValue(),
      methods: ['GET', 'POST'],
      credentials: true,
      preflightContinue: false,,
      allowedHeaders:["Content-Type","X-Requested-With","X-HTTP-Method-Override","Accept"]
    
    callback(null, corsOptions)
  

app.use('*', cors(this.getCorsCoptions));
app.options('*', cors(this.getCorsCoptions));

我在 React Client 端使用 axios 如下

get(url: string) 
    return Axios.get(url, 
      withCredentials: true
    ).then((res: any) => 
      if (res) 
        return res.data;
      
      return ;
    );


post(url: string, data: any) 
    let requestHeaders =  'Content-Type': 'application/json' ;
    return Axios.post(url, data, 
      headers: requestHeaders
      , withCredentials: true
    ).then((res: any) => 
      if (res) 
        return res.data;
      
      return ;
    );

【问题讨论】:

你在服务器上使用express吗? 是的,在服务器上使用 express 我已经发布了答案。尝试将您的 corsOptions.origin 设置为您想要工作的 URL 字符串数组 不确定,但听起来您可能想尝试在响应中添加 Vary: Origin 响应标头。请参阅***.com/a/46735000/441757 和***.com/a/46067554/441757 的答案并查看developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Vary 【参考方案1】:

我找到了解决这个问题的方法。浏览器正在缓存源。 通过在响应中添加以下标头解决了这个问题

Cache-Control: no-store,no-cache,must-revalidate

我还添加了Vary: Origin,但我认为它并没有解决问题 我管理 cors 如下

var whitelist = ['https://www.example.com', 'https://subdomain.example.com'];
router.all("*", (req, res, next) => 
    var origin = req.headers.origin;
    if (whitelist.indexOf(origin) != -1) 
      res.header("Access-Control-Allow-Origin", origin);
    
    res.header("Access-Control-Allow-Headers", ["Content-Type","X-Requested-With","X-HTTP-Method-Override","Accept"]);
    res.header("Access-Control-Allow-Credentials", true);
    res.header("Access-Control-Allow-Methods", "GET,POST");
    res.header("Cache-Control", "no-store,no-cache,must-revalidate");
    res.header("Vary", "Origin");
    if (req.method === "OPTIONS") 
    res.status(200).send("");
      return;
    
    next();
);

路由器在哪里 express.Router()

我希望有人觉得这很有帮助。

【讨论】:

【参考方案2】:

这是因为你正在调用你的函数,你只需要将它传递给中间件

var corsOptions = 
      origin: getOriginValue, // Not origin: getOriginValue()<-no parens,
      methods: ['GET', 'POST'],
      credentials: true,
      preflightContinue: false,,
      allowedHeaders:["Content-Type","X-Requested-With","X-HTTP-Method-Override","Accept"]
    

【讨论】:

你注意到了一个正确的观点,但这并不能解决我的问题【参考方案3】:

您似乎在使用 express。根据他们的文档,您可以将 origin 设置为字符串数组或 RegExp,这应该允许您想要的来源。

https://expressjs.com/en/resources/middleware/cors.html

origin:配置 Access-Control-Allow-Origin CORS 标头。 可能的值:

数组 - 将原点设置为有效原点的数组。 每个来源可以是字符串或正则表达式。例如 ["http://example1.com", /.example2.com$/] 将接受任何请求 来自“http://example1.com”或来自“example2.com”的子域。

基于此,将getOriginValue() 更新为以下内容可能对您有用:

var getOriginValue = () => 
  if (whitelist.indexOf(req.header('origin')) !== -1) 
    return whitelist; // Return array of strings
   else 
    log.error(__filename, 'Not allowed by CORS', origin);
    return false;
  

【讨论】:

以上是关于cors 子域失败的主要内容,如果未能解决你的问题,请参考以下文章

CORS 因请求而失败,带有 OPTIONS(状态为 0 的响应)

子域验证中的 Gitlab ssl 失败

覆盖 cookie 失败 PHP & ASP 跨子域

如何确保我的 CDN 按来源缓存 CORS 请求?

为啥此 CORS 请求失败?

CORS 发布请求失败