由于响应中不存在“Access-Control-Allow-Origin”标头,跨域请求停止工作

Posted

技术标签:

【中文标题】由于响应中不存在“Access-Control-Allow-Origin”标头,跨域请求停止工作【英文标题】:Cross-domain requests stopped working due to no `Access-Control-Allow-Origin` header present in the response 【发布时间】:2015-06-14 01:44:54 【问题描述】:

我有一个使用 Google Apps 脚本创建的错误报告信标,它以我自己的身份运行并且可供“任何人,甚至是匿名的”访问,这应该意味着 X 域请求允许到 GAS。

但是,在代码发布到信标后,我的浏览器现在显示响应中没有 Access-Control-Allow-Origin 标头。

我在这里遗漏了什么吗?这曾经在两个月前有效。只要 GAS 发布供公众访问,那么它设置了Access-Control-Allow-Origin 标头。

在 Google Apps 脚本中:

代码.gs
function doPost(data)
  if(data)
        //Do Something
  
  return ContentService.createTextOutput("status:'okay'", ContentService.MimeType.JSON);

客户端:

脚本.js
$.post(beacon_url, data, null, "json");

【问题讨论】:

【参考方案1】:

在调用内容服务脚本时,我总是发送 JSONP 回调。由于 GAS 不支持 CORS,因此这是确保您的应用在 x 域问题出现时不会中断的唯一可靠方法。

在 jQuery 中调用只需添加“&callback=?”。它会解决其他所有问题。

 var url = "https://script.google.com/macros/s/YourProjectId/exec?offset="+offset+"&baseDate="+baseDate+"&callback=?";
 $.getJSON( url,function( returnValue )...);

在服务器端

function doGet(e)
 var callback = e.parameter.callback;
 //do stuff ...
 return ContentService.createTextOutput(callback+'('+ JSON.stringify(returnValue)+')').setMimeType(ContentService.MimeType.javascript);

【讨论】:

我将此标记为答案,但它有点偏离,因此您可能需要编辑。出于某种原因,在 createTextOutput 中设置内容类型,即使将其设置为 JavaScript 也不能​​解决问题。但是,使用函数 setContentType 并将其设置为 JavaScript 确实有效。另外,在这个用例中,我使用的是 POST,而不是 GET 请求。 啊,是的,JSONP 不适用于 Post。你描述的一切听起来都是正确的。以“我”身份运行应用程序允许访问“匿名”。确保您正在调用已发布的地址而不是开发人员地址。如果所有这些都设置好了,你应该有: Access-Control-Allow-Origin: * 我用 hurl.it 测试了一个小脚本。我看到所有正确的标题都从那里返回。 请注意,如果由于某种原因脚本中有错误,它将返回 text/html MIME 类型而不是 JSON,然后会导致 CORS 错误。所以这也可能是您的问题的原因。【参考方案2】:

我因同样的问题浪费了几个小时。解决方案很简单。

当您将脚本部署为 webapp 时,您会获得两个 URL:一个是 /dev,另一个是 /exec。您应该使用 /exec 之一来发出跨域 POST 请求。 /dev 始终是私有的:它需要被授权并且不设置 *Allow-Origin 标头。

PS.:/exec 似乎被冻结了——它不会反映代码的任何更改,直到您使用新版本字符串手动部署它(部署对话框中的下拉列表)。要使用/dev URL 调试最新版本的脚本,只需安装替代浏览器并禁用其网络安全功能(--disable-web-security 在 GoogleChrome 中)。

【讨论】:

为了将来参考,这篇博文似乎详细说明了这一点:Google Apps Script Content Service - Cross Domain Puzzle。这里也有相当相关的信息:App Script sends 405 response when trying to send a POST request。看起来,/exec 范围只会在 simple requests 的情况下按预期通过 CORS。 @Novack 你拯救了我的一天!将请求 Content-typeapplication/json 更改为 AJAX 默认 application/x-www-form-urlencoded 解决了我的预检 405 问题! 非常感谢您添加有关如何冻结代码的详细信息。我一直在寻找几个小时,困惑的 b/c 我正在尽一切努力,它仍然给我 CO 错误。我很欣赏他们不会自动对其进行版本控制,因此每次更改警报时它不会生成十亿个版本的代码,但同时在其中包含一个注释会很好,“嘿,如果你用新代码部署它,你需要指定一个新版本。”【参考方案3】:

只是为了让像我这样只对 POST 请求感兴趣的人更简单:

function doPost(e)

 //do stuff ...

 var MyResponse = "It Works!";

 return ContentService.createTextOutput(MyResponse).setMimeType(ContentService.MimeType.JAVASCRIPT);


【讨论】:

这在 2018 年似乎对我不起作用。我仍然收到 CORS 错误。 @jj_ 当您部署 web 应用程序时,它们开始使用 /exec URL。更多细节在我下面的回答中。 感谢您更新其他解决方案,是的,这是很久以前的事了!不过仍然适用于某些人。【参考方案4】:

我偶然发现了同样的问题:

在 localhost 上运行网页时,从浏览器调用 /exec-urls 正常 从 https 域调用时引发跨域错误

我试图避免将我的 POST JSON-clientcode 重构为 JSONP(我持怀疑态度,因为以前总是这样)。

可能的修复 #1

幸运的是,我做了一个非 CORS 请求(fetch() 在来自 https 域的浏览器中,使用 mode: no-cors),通常的 CORS 请求再次正常工作。

最后的想法

最后的解释可能是:每个新的 appscript-deployment 都需要一些时间/使用,然后它的配置才真正稳定在服务器级别。

【讨论】:

我得试试这个。自从我第一次发布这个问题以来的 5 年里,也许发生了很大的变化。【参考方案5】:

当我尝试将应用脚本应用程序与另一个 Vue 应用程序集成时,我遇到了类似的 CORS 策略错误问题。

请注意以下配置:

    每次部署的项目版本都应该是NEW。 以 me 身份执行应用,以防您想授予所有人访问权限。 任何人,匿名有权访问应用程序。

希望这对你有用。

【讨论】:

【参考方案6】:

在您的调用应用程序中,只需将 content-type 设置为 text/plain,您就可以将 GAS 返回的 JSON 解析为有效的 json 对象。

这是我的 google 脚本 doPost 函数中的 JSON 对象

var result = 
  status: 200, 
  error: 'None',
  rowID: rowID
;

ws.appendRow(rowContents);

  return ContentService.createTextOutput(JSON.stringify(result))
  .setMimeType(ContentService.MimeType.JSON);  

在这里我从节点 js 调用我的应用脚本 API

           const requestOptions = 
                method: 'POST',
                headers: 'Content-Type': 'text/plain',
                body: JSON.stringify(param1: value, param2:value)
            ;
const response = await fetch(server_URL, requestOptions);
            const data = await response.json();
            console.log(data);
            console.log(data.status);

【讨论】:

【参考方案7】:

我的情况不同,我正以一种非常奇怪的方式面临 CORS 错误。

我的代码工作正常,没有 CORS 错误,直到我添加了一个常量:

const MY_CONST = "...";

Google Apps Script (GAS) 似乎不允许使用 'const' 关键字,GAS 是基于 ES3 或之前 ES5 或类似的东西。 'const' 上的错误重定向到没有 CORS 的错误页面 URL。

参考:https://***.com/a/54413892/5581893

【讨论】:

【参考方案8】:

如果这对所有像我这样的人有所帮助:

我有一个 .js 文件,其中包含我所有的实用程序函数,包括调用 GAS 的函数。我去测试更新时总是忘记清除缓存,所以我经常会收到这种错误,因为缓存的代码使用的是 /dev 链接而不是 /exec 链接。

【讨论】:

【参考方案9】:

以下解决方案对我有用

在 Google Apps 脚本中

function doPost(e) 
  return ContentService.createTextOutput(JSON.stringify(status: "success", "data": "my-data")).setMimeType(ContentService.MimeType.JSON);

在 JavaScript 中

fetch(URL, 
      redirect: "follow",
      method: "POST",
      body: JSON.stringify(DATA),
      headers: 
        "Content-Type": "text/plain;charset=utf-8",
      ,
    )

注意属性redirect: "follow",它非常重要。没有它,它对我不起作用。

【讨论】:

以上是关于由于响应中不存在“Access-Control-Allow-Origin”标头,跨域请求停止工作的主要内容,如果未能解决你的问题,请参考以下文章

为啥在来自 GET :urn/metadata/:guid/properties 的 JSON 响应中不存在 revit 类别属性?

AWS SAM:请求的资源响应中不存在“Access-Control-Allow-Origin”标头

对预检请求的响应未通过访问控制检查:请求的资源中不存在“Access-control-Allow-Origin”标头

Angular 7:对预检请求的响应未通过访问控制检查:请求中不存在“Access-Control-Allow-Origin”标头

由于 Spring MVC 中不存在 URL,验证表单提交按钮在第二次尝试后返回 404

奇偶校验 GUI 错误(getTransactions TypeError: Failed to fetch)