前言
我的Web应用程序将数据存储在
localStorage
。 这很方便,直到我希望用户从不同设备访问该站点时看到相同的东西。 即,需要远程存储。
但是该应用程序“托管”在GitHub Pages上,并且没有服务器部分。 我决定不制造服务器,而是与第三方存储数据。 这具有明显的优势:
- 无需为服务器付费,它不会伤及服务器的稳定性和可用性。
- 更少的代码,更少的错误。
- 用户不需要在我的应用程序中注册(这很烦人)。
- 隐私性更高,并且用户知道他的数据存储在一个他最可能信任我的地方。
首先,选择权落在
remoteStorage.js上 。 他们提供了一个开放的数据交换协议,一个非常不错的API,与Google Drive和Dropbox以及它们的服务器集成的能力。 但是,这条道路最终是死路一条(为什么-一个单独的故事)。
最后,我决定直接使用Google云端硬盘,并将
Google API客户端库 (以下称为GAPI)用作访问它的库。
不幸的是,Google文档令人失望,并且GAPI库看起来还没有完成,而且,它有多个版本,而且不清楚哪个是有问题的。 因此,必须从文档,StackOverflow上的问题和答案以及Internet上的随机帖子中分几部分收集解决问题的方法。
如果您决定在应用程序中使用Google云端硬盘,希望本文能为您节省时间。
准备工作
以下是有关如何获取用于Google API的密钥的说明。 如果您不感兴趣,请直接进入下一部分。
接收钥匙在Google Developer Console中,
创建一个新项目,输入名称。
在“控制面板”中,单击“启用API和服务”,然后打开Google云端硬盘。
接下来,转到“ API和服务->凭据”部分,单击“创建凭据”。 您需要做三件事:
- 配置“ OAuth访问请求窗口”。 输入应用程序的名称,“授权域”部分中的域以及指向应用程序主页的链接。 其他字段是可选的。
- 在“凭据”部分中,单击“创建凭据”->“ OAuth客户端标识符”。 选择类型“ Web应用程序”。 在设置窗口中,添加“允许的Javascript源”和“允许的重定向URI”:
- 您的域(必填)
http://localhost:8000
(可选,可在本地工作)。

- 在“凭据”部分中,单击“创建凭据”->“ API密钥”。 在关键设置中,指定限制:
- 允许的应用程序类型-> HTTP引荐来源网址(网站)
- 接受来自以下引荐来源(站点)的HTTP请求->您的域和本地主机(如第2点所示)。
- 有效的API-> Google Drive API

凭据部分应如下所示:

至此我们完成。 我们传递给代码。
初始化和登录
Google建议的启用GAPI的方法是将以下代码粘贴到HTML中:
<script src="https://apis.google.com/js/api.js" onload="this.onload=function(){}; gapi.load('client:auth2', initClient)" onreadystatechange="if (this.readyState === 'complete') this.onload()"> </script>
加载库后,将调用
initClient
函数,我们必须编写自己的函数。 其典型外观如下:
function initClient() { gapi.client.init({
对于数据存储,我们将使用所谓的
Application Data文件夹 。 与常规文件夹相比,它的优点是:
- 用户不会直接看到它:来自其中的文件不会阻塞他的个人空间,并且他也不会破坏我们的数据。
- 其他应用程序看不到它,也不能破坏它。
- 上面提到的范围使应用程序可以访问它,但不能访问用户的其余文件。 也就是说,我们不会通过请求访问一个人的个人数据来吓scar一个人。
成功初始化Google API后,该函数将执行以下操作:
- 开始捕获登录/注销事件-最有可能,应该始终这样做。
- 初始化应用程序。 您可以根据需要在加载和初始化GAPI之前完成此操作。 如果Google不可用,我的初始化过程会稍有不同。 可能有人会说这种情况不会发生:)但是,首先,您将来可以拥有密钥和访问权限。 其次,例如在中国,谷歌被禁止。
登录和注销很简单:
function isGapiLoaded() { return gapi && gapi.auth2 } function logIn() { if (isGapiLoaded()) {
您将在
onSignIn
处理程序中收到登录结果:
function isLoggedIn() { return isGapiLoaded() && gapi.auth2.getAuthInstance().isSignedIn.get() } function onSignIn() { if (isLoggedIn()) {
不幸的是,使用文件并不是很明显。
无极助手
GAPI不返回正常的承诺。 取而代之的是,使用了它自己的Thennable接口,该接口与Promise类似,但不完全相同。 因此,为了方便工作(主要是使用
async/await
),我们将提供一个小助手:
function prom(gapiCall, argObj) { return new Promise((resolve, reject) => { gapiCall(argObj).then(resp => { if (resp && (resp.status < 200 || resp.status > 299)) { console.log('GAPI call returned bad status', resp) reject(resp) } else { resolve(resp) } }, err => { console.log('GAPI call failed', err) reject(err) }) }) }
此函数将GAPI方法和参数作为第一个参数,并返回Promise。 然后,您将看到如何使用它。
处理文件
您应该永远记住,
Google云端硬盘上的文件名不是唯一的 。 您可以创建任意数量的具有相同名称的文件和文件夹。 只有标识符是唯一的。
对于基本任务,您不需要使用文件夹,因此下面的所有功能都可以使用Application Data文件夹根目录中的文件。 注释指示需要更改以使用文件夹的内容。 Google的文档在这里 。
创建一个空文件
async function createEmptyFile(name, mimeType) { const resp = await prom(gapi.client.drive.files.create, { resource: { name: name,
此异步函数创建一个空文件并返回其标识符(字符串)。 如果已经存在这样的文件,则将创建一个具有相同名称的新文件,并返回其ID。 如果不想这样做,则必须首先检查是否没有相同名称的文件(请参见下文)。
Google云端硬盘不是完整的数据库。 例如,如果您希望多个用户同时在不同设备上使用同一Google帐户工作,则可能由于缺少交易而导致解决冲突的问题。 对于此类任务,最好不要使用Google云端硬盘。
处理文件内容
GAPI(用于基于浏览器的JavaScript)没有提供处理文件内容的方法(很奇怪,不是吗?)。 相反,有一个通用的
request
方法(一个简单的AJAX请求的瘦包装器)。
通过反复试验,我得出以下实现:
async function upload(fileId, content) {
档案搜寻
async function find(query) { let ret = [] let token do { const resp = await prom(gapi.client.drive.files.list, {
如果未指定
query
,则此函数返回应用程序文件夹中的所有文件(具有
id
和
name
字段的对象数组),并按创建时间排序。
如果您指定
query
字符串(语法
在此处描述),它将仅返回与查询匹配的文件。 例如,要检查是否
config.json
名为
config.json
的文件,您需要执行
if ((await find('name = "config.json"')).length > 0) {
删除文件
async function deleteFile(fileId) { try { await prom(gapi.client.drive.files.delete, { fileId: fileId }) return true } catch (err) { if (err.status === 404) { return false } throw err } }
此函数按ID删除文件,如果删除成功,则返回
true
否则返回
false
。
同步处理
建议该程序主要与
localStorage
,并且Google Drive仅用于同步
localStorage
数据。
以下是一个简单的配置同步策略:
- 通过登录从Google云端硬盘下载新配置,然后每3分钟覆盖本地副本;
- 本地更改已注入Google云端硬盘,并覆盖其中的内容;
- 配置文件
fileID
缓存在localStorage
以加快工作速度并减少请求数量; - 正确处理(错误)的情况是Google云端硬盘具有多个配置文件,并且有人删除了我们的配置文件或将其破坏了。
- 同步详细信息不会影响其余的应用程序代码。 要使用配置,您仅使用两个函数:
getConfig()
和saveConfig(newConfig)
。
在实际的应用程序中,您可能希望在加载/卸载配置时实现更灵活的冲突处理。
结论
在我看来,Google云端硬盘上网站的数据存储非常适合小型项目和原型制作。 它不仅易于实现和支持,而且还有助于减少Universe中不必要实体的数量。 我希望,如果您选择此路径,我的文章将帮助您节省时间。
PS实际项目的代码
位于GitHub上 ,
您可以在此处尝试。