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/goo...</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...

  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)
}

相关文档


米花儿团儿
1.3k 声望75 粉丝

引用和评论

0 条评论