Google Development Api功能开发使用示例

Sample1:授权

概述

主要分为五步:

  1. 加载api工具库

  2. 登陆

  3. scopes授权

  4. 加载对应的工具文档

    • 工具文档决定了调用gapi.client.*对象下的哪一个服务
  5. 根据工具文档中的resources字段调用方法

加载gapi工具库

gapi === google application interface

  <script src="https://apis.google.com/js/api.js"></script>

该工具库会全局注册gapi对象。

Notes: gapi的文档<<u>https://github.com/google/google-api-javascript-client/blob/master/docs/reference.md</u>>

加载授权模块

  gapi.load("client:auth2", function() {
    gapi.auth2.init({
      client_id: CLIENTID,
      // cookiepolicy: 'single_host_origin',
      plugin_name: 'hello' // 必填,可以是任意值 —— 不填,会报错 {error: "popup_closed_by_user"}
    });
  });

登陆且授权

  <button onclick="authenticate().then(loadClient)">authorize and load</button>

点击按钮后,授权服务,加载需要的服务API文档(gapi根据加载的文档会动态生成对应的服务方法)。

  const scopes = [
    "https://www.googleapis.com/auth/drive",
    "https://www.googleapis.com/auth/drive.appdata",
    "https://www.googleapis.com/auth/drive.file",
    "https://www.googleapis.com/auth/drive.metadata",
    "https://www.googleapis.com/auth/drive.metadata.readonly",
    "https://www.googleapis.com/auth/drive.photos.readonly",
    "https://www.googleapis.com/auth/drive.readonly"
  ] // 用户授权可访问的服务列表
  function authenticate() {
    return gapi.auth2.getAuthInstance()
      .signIn({
        scope: scopes.join(" ")
      })
      .then(
        function() {
          console.log("Sign-in successful");
        },
        function(err) {
          console.error("Error signing in", err);
        }
      );
  }
  function loadClient() {
    // 有了授权操作,就不需要设置ApiKey了,二者冲突<https://stackoverflow.com/questions/17436940/google-simple-api-key-stopped-working>
    /**
      * 以当前用户身份调取Api —— 使用access_token
      * 以开发者身份调用API —— 使用API key
    */
    // gapi.client.setApiKey(CLIENTSECRET);
    return gapi.client.load("https://content.googleapis.com/discovery/v1/apis/drive/v3/rest")
      .then(
        function() {
          console.log("GAPI client loaded for API");
        },
        function(err) {
          console.error("Error loading GAPI client for API", err);
        }
      );
  }

调用方法

 <button onclick="execute()">execute</button>

直接浏览器打开https://content.googleapis.com/discovery/v1/apis/drive/v3/rest,查找对应的resources字段,调用对应的methods即可。

  function execute() {
    return gapi.client.drive.files.list({})
      .then(
        function(response) {
          // Handle the results here (response.result has the parsed body).
          console.log("Response", response);
        },
        function(err) {
          console.error("Execute error", err);
        }
      );
  }

完整代码

<!DOCTYPE html>
<html>
  <head>
    <title>Drive API Quickstart</title>
    <meta charset="utf-8" />
  </head>
  <body>
    <p>Drive API Quickstart</p>

    <!--Add buttons to initiate auth sequence and sign out-->
    <button onclick="authenticate().then(loadClient)">authorize and load</button>
    <button onclick="execute()">execute</button>

    <pre id="content" style="white-space: pre-wrap;"></pre>

    <script src="https://apis.google.com/js/api.js"></script>
    <script type="text/javascript">
      const CLIENTID = '<your client_id>'
      const CLIENTSECRET = '<your client_secret>'
      const scopes = [
        "https://www.googleapis.com/auth/drive",
        "https://www.googleapis.com/auth/drive.appdata",
        "https://www.googleapis.com/auth/drive.file",
        "https://www.googleapis.com/auth/drive.metadata",
        "https://www.googleapis.com/auth/drive.metadata.readonly",
        "https://www.googleapis.com/auth/drive.photos.readonly",
        "https://www.googleapis.com/auth/drive.readonly"
      ] // 用户授权可访问的服务列表
      function authenticate() {
        return gapi.auth2.getAuthInstance()
          .signIn({
            scope: scopes.join(" ")
          })
          .then(
            function() {
              console.log("Sign-in successful");
            },
            function(err) {
              console.error("Error signing in", err);
            }
          );
      }
      function loadClient() {
        // 有了授权操作,就不需要设置ApiKey了,二者冲突<https://stackoverflow.com/questions/17436940/google-simple-api-key-stopped-working>
        /**
         * 以当前用户身份调取Api —— 使用access_token
         * 以开发者身份调用API —— 使用API key
        */
        // gapi.client.setApiKey(CLIENTSECRET);
        return gapi.client.load("https://content.googleapis.com/discovery/v1/apis/drive/v3/rest")
          .then(
            function() {
              console.log("GAPI client loaded for API");
            },
            function(err) {
              console.error("Error loading GAPI client for API", err);
            }
          );
      }
  // Make sure the client is loaded and sign-in is complete before calling this method.
      function execute() {
        return gapi.client.drive.files.list({})
          .then(
            function(response) {
              // Handle the results here (response.result has the parsed body).
              console.log("Response", response);
            },
            function(err) {
              console.error("Execute error", err);
            }
          );
      }
      gapi.load("client:auth2", function() {
        gapi.auth2.init({
          client_id: CLIENTID,
          // cookiepolicy: 'single_host_origin',
          plugin_name: 'hello' // 必填,可以是任意值 —— 不填,会报错 {error: "popup_closed_by_user"}
        });
      });
    </script>
  </body>
</html>

Sample2:获取access_token

相关资源

   <script async defer src="https://apis.google.com/js/api.js" onload="gapiLoaded()"></script>
  <script async defer src="https://accounts.google.com/gsi/client" onload="gisLoaded()"></script>

获取用户实例

  tokenClient = google.accounts.oauth2.initTokenClient({
    client_id: CLIENT_ID,
    scope: SCOPES,
    callback: '', // defined later
  });

账号登陆检测

  if (gapi.client.getToken() === null) {
    // Prompt the user to select a Google Account and ask for consent to share their data
    // when establishing a new session.
    tokenClient.requestAccessToken({prompt: 'consent'});
  } else {
    // Skip display of account chooser and consent dialog for an existing session.
    tokenClient.requestAccessToken({prompt: ''});
  }

登陆后的回调

  tokenClient.callback = async (resp) => {
    if (resp.error !== undefined) {
      throw (resp);
    }
    document.getElementById('signout_button').style.visibility = 'visible';
    document.getElementById('authorize_button').innerText = 'Refresh';
    await listFiles();
  };

退出账号

  const token = gapi.client.getToken();
  if (token !== null) {
    google.accounts.oauth2.revoke(token.access_token);
    gapi.client.setToken('');
  }

全部代码

<!DOCTYPE html>
<html>
  <head>
    <title>Drive API Quickstart</title>
    <meta charset="utf-8" />
  </head>
  <body>
    <p>Drive API Quickstart</p>

    <!--Add buttons to initiate auth sequence and sign out-->
    <button id="authorize_button" onclick="handleAuthClick()">Authorize</button>
    <button id="signout_button" onclick="handleSignoutClick()">Sign Out</button>

    <pre id="content" style="white-space: pre-wrap;"></pre>

    <script type="text/javascript">
      const CLIENT_ID = '<your-client_id>';
      const API_KEY = '<your-api_key>';

      const DISCOVERY_DOC = 'https://www.googleapis.com/discovery/v1/apis/drive/v3/rest';
      const SCOPES = 'https://www.googleapis.com/auth/drive.metadata.readonly';

      let tokenClient;
      let gapiInited = false;
      let gisInited = false;

      document.getElementById('authorize_button').style.visibility = 'hidden';
      document.getElementById('signout_button').style.visibility = 'hidden';

      function gapiLoaded() {
        gapi.load('client', initializeGapiClient);
      }

      async function initializeGapiClient() {
        await gapi.client.init({
          discoveryDocs: [DISCOVERY_DOC],
        });
        gapiInited = true;
        maybeEnableButtons();
      }
      function gisLoaded() {
        tokenClient = google.accounts.oauth2.initTokenClient({
          client_id: CLIENT_ID,
          scope: SCOPES,
          callback: '', // defined later
        });
        gisInited = true;
        maybeEnableButtons();
      }

      function maybeEnableButtons() {
        if (gapiInited && gisInited) {
          document.getElementById('authorize_button').style.visibility = 'visible';
        }
      }

      function handleAuthClick() {
        tokenClient.callback = async (resp) => {
          if (resp.error !== undefined) {
            throw (resp);
          }
          document.getElementById('signout_button').style.visibility = 'visible';
          document.getElementById('authorize_button').innerText = 'Refresh';
          await listFiles();
        };

        if (gapi.client.getToken() === null) {
          // Prompt the user to select a Google Account and ask for consent to share their data
          // when establishing a new session.
          tokenClient.requestAccessToken({prompt: 'consent'});
        } else {
          // Skip display of account chooser and consent dialog for an existing session.
          tokenClient.requestAccessToken({prompt: ''});
        }
      }

      /**
       *  Sign out the user upon button click.
       */
      function handleSignoutClick() {
        const token = gapi.client.getToken();
        if (token !== null) {
          google.accounts.oauth2.revoke(token.access_token);
          gapi.client.setToken('');
          document.getElementById('content').innerText = '';
          document.getElementById('authorize_button').innerText = 'Authorize';
          document.getElementById('signout_button').style.visibility = 'hidden';
        }
      }

      /**
       * Print metadata for first 10 files.
       */
      async function listFiles() {
        let response;
        try {
          response = await gapi.client.drive.files.list({
            'pageSize': 10,
            'fields': 'files(id, name)',
          });
        } catch (err) {
          document.getElementById('content').innerText = err.message;
          return;
        }
        const files = response.result.files;
        if (!files || files.length == 0) {
          document.getElementById('content').innerText = 'No files found.';
          return;
        }
        // Flatten to string to display
        const output = files.reduce(
            (str, file) => `${str}${file.name} (${file.id}\n`,
            'Files:\n');
        document.getElementById('content').innerText = output;
      }
    </script>
    <script async defer src="https://apis.google.com/js/api.js" onload="gapiLoaded()"></script>
    <script async defer src="https://accounts.google.com/gsi/client" onload="gisLoaded()"></script>
  </body>
</html>

Sample3:创建文件

HTTP请求

Body的组装:

用自定义boundary边界字符串标识每个部分,每部分都有两个连字符打头。

此外,在结束位置,仍以自定义boundary边界字符串 + 两个连字符结尾。

async function upload () {
  console.log('-------upload---token------', gapi.client.getToken())
  let callback
  var content = 'this is my secret'; // 新文件的正文
  var blob = new Blob([content], { type: "text/plain"});
  const boundary = '-------314159265358979323846';
  const delimiter = "\r\n--" + boundary + "\r\n";
  const close_delim = "\r\n--" + boundary + "--";

  var reader = new FileReader();
  reader.readAsBinaryString(blob);
  reader.onload = function(e) {
    var contentType = 'application/octet-stream';
    var metadata = {
      'name': 'aaa.txt',
      'mimeType': contentType
    };

    var base64Data = btoa(reader.result);
    var multipartRequestBody =
        delimiter +
        'Content-Type: application/json\r\n\r\n' +
        JSON.stringify(metadata) +
        delimiter +
        'Content-Type: ' + contentType + '\r\n' +
        'Content-Transfer-Encoding: base64\r\n' +
        '\r\n' +
        base64Data +
        close_delim;

    var request = gapi.client.request({
        'path': '/upload/drive/v3/files',
        'method': 'POST',
        'params': {'uploadType': 'multipart'},
        'headers': {
          'Content-Type': 'multipart/mixed; boundary="' + boundary + '"'
        },
        'body': multipartRequestBody});
    if (!callback) {
      callback = function(file) {
        console.log(file)
      };
    }
    request.execute(callback);
  }
}

axios请求

formData组装顺序:

Meatadata >> file

否则,会报错https://developers.google.com/drive/api/guides/manage-uploads#http_1

  var formData = new FormData();
  var content = 'this is my secret'; // 新文件的正文
  var blob = new Blob([content], { type: "text/plain"});
  var metadata = {
    'name': 'customfile.txt', // Filename at Google Drive
    'mimeType': 'text/plain', // mimeType at Google Drive
    // TODO [Optional]: Set the below credentials
    // Note: remove this parameter, if no target is needed
    // 'parents': ['SET-GOOGLE-DRIVE-FOLDER-ID'], // Folder ID at Google Drive which is optional
  };
  formData.append('metadata', new Blob([JSON.stringify(metadata)], { type: 'application/json' }));
  formData.append("file", blob);
  axios.post(
    'https://www.googleapis.com/upload/drive/v3/files',
    formData,
    {
      headers: {
        Authorization: `Bearer ${access_token}`,
        'Content-Type': 'multipart/form-data'
      },
      params: {
        uploadType: 'multipart',
        supportsAllDrives: true
      },
    }
  )

Sample4: 创建文件夹

var parentId = '';//some parentId of a folder under which to create the new folder
var fileMetadata = {
  'name' : 'New Folder',
  'mimeType' : 'application/vnd.google-apps.folder',
  'parents': [parentId]
};
gapi.client.drive.files.create({
  resource: fileMetadata,
}).then(function(response) {
  switch(response.status){
    case 200:
      var file = response.result;
      console.log('Created Folder Id: ', file.id);
      break;
    default:
      console.log('Error creating the folder, '+response);
      break;
    }
});

Sample5:读取文件内容

追加?alt=media可查看文件内容,否则,返回文件的metadata。

async function handleExport (_event: any, fileId = '') {
  const res = await axios.get(
    `https://www.googleapis.com/drive/v3/files/${fileId}`,
    {
      params: {
        alt: 'media'
      },
      headers: {
        Authorization: `Bearer ${accessToken}`,
      },
    }
  )
  if (res.status === 200) {
    return res.data
  }
}

Sample6: 获取用户信息

查看用户所有信息,可传fields: "*"

async function handleUserInfo () {
  const res = await gapi.client.drive.about.get({
    fields: "user, kind"
  });
  console.log('-------------uesr--------', res)
}

相关文档

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,236评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,867评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,715评论 0 340
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,899评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,895评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,733评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,085评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,722评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,025评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,696评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,816评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,447评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,057评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,009评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,254评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,204评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,561评论 2 343

推荐阅读更多精彩内容