Google 来自浏览器的联系人 API 被 CORS 策略阻止

Google Contacts API from browser blocked by CORS policy

我在开发环境中通过浏览器向 Google 联系人 API 发出请求时遇到一些问题。

我正在尝试从托管在 https://localhost:3001 by making an XHR request to https://www.google.com/m8/feeds/contacts/default/thin?alt=json&access_token=MYTOKEN&max-results=5000&v=3.0

的网络应用程序中请求联系人供稿

我们之前一直在使用 JSONP 发出此请求(正如其他各种帮助论坛中所建议的那样),但最近开始失败并出现此错误:

Refused to execute script from 'https://www.google.com/m8/feeds/contacts/default/thin?alt=json&access_token=MYTOKEN&max-results=5000&v=3.0&callback=jQuery33107099178438653957_1542737952472&_=1542737952473' because its MIME type ('application/json') is not executable, and strict MIME type checking is enabled.

我知道这现在失败了,因为浏览器正在检查响应的 mimetype 并且因为它不是 application/javascript,它不应该被评估为脚本,因此 JSONP 不起作用。我们试图请求 application/javascript,但似乎 API 不会给我们那个 mimetype 的响应。

现在我们正试图清理我们的行为,但我们 运行 陷入了一个 CORS 问题,我想这就是整个互联网首先告诉彼此使用 JSONP 的原因。

当我们尝试在没有 JSONP 的情况下发出请求时,出现此错误

Access to XMLHttpRequest at 'https://www.google.com/m8/feeds/contacts/default/thin?alt=json&access_token=MYTOKEN&max-results=5000&v=3.0' from origin 'https://localhost:3001' 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.

然而,在 Google support forum, someone suggested using googleapis.com instead of google.com. As a lark, we tried it, and it does indeed work. My problem now is I have no idea why this works or it it will continue to work. The docs 的深处没有提到使用这个新主机 - 他们确实提到 googleapis.com URL 作为 read-only OAuth 范围,但这似乎与这个问题无关。 googleapis.com 确实是我们应该用来从浏览器获取联系人的新主机名吗?

编辑:包括发出请求的代码

const params = $.param({
  alt: 'json',
  access_token: 'MYTOKEN',
  'max-results': 5000,
  v: '3.0'
})
const url = `https://www.google.com/m8/feeds/contacts/default/thin?${params}` # when I change this to www.googleapis.com it works
$.get(url, responseHandler)

编辑:在我的浏览器出于某种原因发送的 CORS 预检选项请求中包含请求 headers:

Accept: text/html,application/xhtml+xm…plication/xml;q=0.9,*/*;q=0.8
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.5
Access-Control-Request-Headers: x-csrf-token
Access-Control-Request-Method: GET
Cache-Control: no-cache
Connection: keep-alive
Host: www.google.com
Origin: https://localhost:3001
Pragma: no-cache
User-Agent: Mozilla/5.0 (Macintosh; Intel …) Gecko/20100101 Firefox/63.0

感谢@sideshowbarker 的评论,我们发现我们有一个 jQuery ajax 预过滤器配置为向任何 [=16= 添加 x-csrf-token header ] ajax请求。这导致浏览器发送失败的 CORS 预检选项请求。

在我们的例子中,x-csrf-token header 的来源是一个名为 ember-cli-rails-addon 的依赖项,它将 x-csrf-token 添加到所有请求中。该项目 here 有一个 PR 可以解决该问题。