我正在尝试从我的javascript代码中使用Google Places API。
(假设所有其他事情 - api 密钥、从谷歌控制台启用 API 等已经完成(。
当我尝试直接从我的javascript访问Places API时,它给了我一个CORS错误,我认为这是因为我的域没有在Places API中列入白名单。
为了规避这一点,建议的方法是使用 Javascript Maps SDK。 SDK 不是一个 npm 模块,它是一个托管的 JS 文件,与 Places API 位于同一域中。
我试图理解的是这个用Javascript编写的SDK如何调用Places API并且不会收到CORS错误。
它是否与地图SDK和地点API从同一域提供的事实有关?
这些 api 调用不应该在我的域上下文中执行并因 CORS 而被阻止吗?
如果 SDK 是 npm 包,它还能工作吗?
SDK 进行的 api 调用与 Places API 不完全相同,但它位于同一域中。
/maps/api/place/autocomplete/json?input=Ben&key=KEY
与
/maps/places/api/js/AutocompleteService.GetPredicitons
我已经尝试了直接从我的javascript调用/maps/places/api/js/AutocompleteService.GetPredicittons,但它也给了我CORS错误。
TL;博士;Google SDK 使用 JSON P,方法是使用脚本标记进行调用并指定回调。这与被同源策略阻止的 XHR 请求不同。
解释:
脚本的托管位置无关紧要,因为它是在域的上下文中执行的,因此浏览器进行的任何 api 调用都将源作为您的域,而不是托管脚本的域。
这意味着,如果 SDK 从 maps.googleapis.com/maps/... 调用端点,它确实如此,则应以 origin 作为我的域发出请求,并且应该给出 CORS 错误,但它仍在返回数据。
在进一步检查时,我发现SDK没有发出xhr请求(由于同源策略而被阻止(,而是创建脚本标签并处理服务器返回的响应。它使用 jsonp 通过在 url 中提供回调来做到这一点,以便服务器发送包装在该回调中的响应,一旦脚本被下载并执行,它就会运行函数,sdk 现在可以处理数据。
关于安全性和一般理解的一些要点:
-
sdk 需要一个 api 密钥,它会随每次 api 调用一起发送。因此,如果您通过传入密钥(看起来像这样:https://maps.googleapis.com/maps/api/js?key=KEY&libraries=places(从托管 url 下载 sdk 并分发它,您基本上将分发包含硬编码密钥的 sdk 脚本。(当然,如果您对 api 密钥设置了限制,这不会有任何特定的安全隐患,您应该这样做,因为您的密钥在网络调用中对用户可见(
-
即使我了解 sdk 正在使用 jsonp 工作,并且我能够进行完全相同的 api 调用,当我更改需要建议的查询文本并且没有更改任何其他内容(所有其他参数都相同(时,调用仍然失败并显示 403。这是因为,sdk 似乎在参数中发送了一个令牌,该令牌以某种方式派生自查询文本。因此,绕过 sdk 并自己创建这些调用并不容易,为此您需要弄清楚令牌生成算法。
-
最重要的是,由于我只启用了 Referer 的 api 密钥安全性,所以无论如何谷歌不会允许任何其他引用者使用我的密钥,即使该密钥在我的应用程序用户的"网络"选项卡中可见。