如何通过 GitHub API 获取较大的文件

译文 精选
开发
我在 Hackernoon 上有一个任务,该任务需要使用 GitHub API 获取一些文件。起初,我认为这将会是一个简单的 GET 请求,但很快我意识到是我把问题想简单了。

我在 Hackernoon 上有一个任务,该任务需要使用 GitHub API 获取一些文件。起初,我认为这将会是一个简单的 GET 请求,但很快我意识到是我把问题想简单了。从刚开始 GET 请求的结果来看,我需要使用一些我目前还没有掌握的方法,因为需要获取的文件非常大,最终在这个问题上我花费了两天的时间。

现在是时候写一篇文章了,这样以后我和其他人就都不必在一个简单的问题上花费太多时间了。

在本文中,我将向您展示如何使用 GitHub API 获取大于 1MB 的文件。学习完本文章后,您将会了解以下内容:

  • 如何使用 GitHub API 获取大文件
  • 如何使用commit SHA
  • 使用 blob  base64 编码数据

在本文中,我将使用了来自 HackerNoon 的年度创业大赛(https://startups.hackernoon.com/faq?ref=hackernoon.com)的数据。 该部分数据在 GitHub上是公开的。

获取小于1MB的文件

获取较小的文件很简单,您只需将三个参数传递给 API。 首先是所有者的姓名,可以是您的用户名。第二个是 repo,它是提交文件的存储库。path 是文件的绝对路径。

下面是我使用codepen创建的一小段代码,供大家参考。

let fileSHA, fileBlob, fileContent, file

const getFileSHA = async () => {
try {
const response = await fetch(
"https://api.github.com/repos/hackernoon/where-startups-trend/contents/2021/"
);
const data = await response.json();
// console.log(data);

fileSHA = data[1].sha
console.log(fileSHA);

} catch (error) {
console.log(error);
}

getFileBlob()
}

const getFileBlob = async (fileSHA)=> {
try {
const response = await fetch(
`https://api.github.com/repos/hackernoon/where-startups-trend/git/blobs/a51a49dfc2bd7be262bd59bb85e85271ea0c18cd`
);
const data = await response.json();

fileBlob = data.content
convertBlob(fileBlob)
} catch (error) {
console.log(error);
}
}

const convertBlob = async blob => {
// console.log(blob)
try {

// const fileContents = Buffer.from(blob, "base64").toString()
// file = JSON.parse(fileContents)
// file = JSON.parse(fileContents)

fileContents = base64EncodeUnicode(blob)
file = JSON.parse(fileContents)
console.log(file)

} catch(error) {
console.log(error)
}
}

function base64EncodeUnicode(str) {
utf8Bytes = decodeURIComponent(str).replace(/%([0-9A-F]{2})/g, function (match, p1) {
return String.fromCharCode('0x' + p1);
});

return atob(utf8Bytes);
}


getFileSHA()

为了更好地理解上述代码,我创建了四个变量,用来存储不同状态下的数据。

let fileSHA, fileBlob, fileContent, file
  • fileSHA用来存储我们想要获取的文件的 SHA
  • fileBlob存储从API 获取的 blob。
  • fileContent用于存储解码后的字符串。
  • file包含我们真正需要的数据。

您可以在下一节中找到对应的参考代码,只需将文件夹路径更改为实际文件路径(带文件扩展名)。

获取大文件

但是,如果您需要获取大于 1MB 的文件,API 会抛出错误。这是因为上述方式不支持大文件。若需要获取大文件,我们必须改为使用 Github API。

这类API允许您从 Git 存储库和列表中读取和写入原始 Git 对象,也可以更新 Git 引用(Git references)。 该类API主要适用于blob,这正是本文的重点。

Git将大文件转换为base64 编码的 blob,而不是存储整个文件,以便获得更好的性能。因此,当您请求同一个文件时,希望您使用返回 blob的接口。

要获取blob,您需要传递文件对应的SHA。您可能想问,什么是 SHA?又该如何获得它?

每次提交新文件时,git 都会创建一个名为 hash 或 SHA 的唯一ID 来记录此次更改。但有时可能会导致问题,我将在本文末尾讨论这个问题。

获取文件对应的SHA

现在,我们需要找到一种方法来获取所需文件的“SHA”。GitHub API有一个接口,可以用来同我们需要使用的文件内容进行交互。

GET /repos/{owner}/{repo}/contents/{path}

作为响应,我们得到一个有关对象的数组,其中包含目录中每个文件的元数据。 元数据中包含我们可以存储和后面会用到的SHA。

const getFileSHA = async () => {
try {
const response = await fetch(
"<https://api.github.com/repos/hackernoon/where-startups-trend/contents/2021/>"
);
const data = await response.json();
console.log(data);

fileSHA = data[3].sha
console.log(fileSHA);

} catch (error) {
console.log(error);
}

getFileBlob(fileSHA)
}

data[3].sha 是具有 votes_by_region.jso n 的 SHA,因此我们将其存储在 fileSHA 中以备后面使用。 下图是控制台的输出情况:

获取对应的Blob

我们已经获取了blob所需SHA。 我们需要使用不同的接口来处理 blob。 这个接口与上一个接口相似,但该接口需要将文件对应的SHA 作为第三个参数传递。

GET /repos/{owner}/{repo}/git/blobs/{file_sha}

当我们向下面的函数提供文件的 SHA 作为参数时,就可以获取对应blob。

const getFileBlob = async (fileSHA)=> {
try {
const response = await fetch(
`https://api.github.com/repos/hackernoon/where-startups-trend/git/blobs/${fileSHA}`
);
const data = await response.json();

fileBlob = data.content
convertBlob(fileBlob)
} catch (error) {
console.log(error);
}
}

此请求返回一个 base64 编码的 blob。 Base64 是一种以 ASCII 字符串格式表示二进制数据的编码方案。 当我们需要在不进行任何修改的情况下存储或传输数据时,它很有用。控制台输出看起来很乱,但这就是 base64 编码数据的方式。

将 Blob 转换为可使用的数据

在最后一步,我们需要将以 base64 编码的 blob 转换为我们可以在程序中使用的数据。 但这一步非常令人沮丧,因为标准方法在某些情况下似乎不起作用。在这个问题上花了几个小时后,我找到了三个解决方案。

1.最简单的方法

这是 JavaScript 原生支持的标准方式。 atob() 是一个 Web API 接口,可将 base64 编码数据解码为纯字符串。

atob 把读取的 ASCII 转化为二进制,因为它将以 ASCII 编码的 base64 数据转换为二进制形式。 输出将是一个解码后的字符串。 要将其转换为其原始数据类型,我们使用 JSON.parse()。

fileContents = atob(blob)
file = JSON.parse(fileContents)

2.第二种方法

如果上述方法抛出错误,你可以使用Node.js 提供了一个方法 Buffer.from()。 它将要解码的字符串作为第一个参数,将编码技术作为第二个参数。

try {
const fileContents = Buffer.from(fileBlob, "base64").toString()
file = JSON.parse(blobToString)

console.log(file)
} catch(error) {
console.log(error)
}

3.第三种方法

如果您在前端工作,则前面提到的方法很有可能不起作用。 在这种情况下,创建一个使用 decodeURIComponent 的函数。

// define the function
const decodeBase64 = str => {
utf8Bytes = decodeURIComponent(str).replace(/%([0-9A-F]{2})/g, function (match, p1) {
return String.fromCharCode('0x' + p1);
});

return atob(utf8Bytes);
}

您可以通过传递 fileBlob 作为参数来调用此函数,并获取您需要的解码字符串。

fileContents = decodeBase64(fileBlob)
file = JSON.parse(fileContents)

console.log(file)

依然不能正常工作

此时,您可以尝试两种最终选择。您可以使用 FileReader API 或以不同的方式使用 decodeURIComponent。

1.FileReader API:您可以在此处找到 MDN 文档(https://developer.mozilla.org/en-US/docs/Web/API/FileReader?ref=hackernoon.com)

2.decodeURIComponent:请参阅 Rajeev Singh关于处理 16 位编码字符串的博客。(https://www.base64decoder.io/javascript/?ref=hackernoon.com)

或者,您也可以尝试一个名为 js-base64(https://www.npmjs.com/package/js-base64?ref=hackernoon.com)的 NPM 包。我自己没有使用过,所以无法提供建设性的意见。

注意

如前所述,SHA 是在每次修改文件时都会更改的具有唯一性的ID号。此外,由于我们在 getFileSHA() 函数中有一个硬编码的对象索引,如果您在目录中添加或删除文件,API 可能会以不同文件的 SHA 响应。

为了解决这个问题,您可以明确指明的文件名而不是索引,这样您就可以在提交新更改后保持函数不变。

总结和 TL;DR

1.Git 以 blob 格式存储较大的文件,因此我们使用 GitHub 数据库 API 来获取大于 1MB 的文件。

2.我们需要提供用户名、repo 名称和文件的 SHA 来获取 blob。

3.为了获取 SHA,我们需要向接口提供文件夹路径并将其存储在变量中。

4.之后我们需要将 SHA 作为参数传递给另一个接口并获得一个 base64 编码的 blob。

5.必须将 blob 解码为纯字符串,然后使用 JSON.parse() 将其转换为原始格式,然后才能使用它。

更多参考资料

GitHub 存储库的内容(https://docs.github.com/en/rest/reference/repos?ref=hackernoon.com#contents)

Git 数据库(https://docs.github.com/en/rest/reference/git?ref=hackernoon.com)

Git 数据库 API 入门(https://docs.github.com/en/rest/guides/getting-started-with-the-git-database-api?ref=hackernoon.com)

译者介绍

赵青窕,51CTO社区编辑,从事多年驱动开发。研究兴趣包含安全OS和网络安全领域,发表过网络相关专利。

原文标题:How to Fetch Large Data Files Through GitHub API,作者:Kaushal Joshi

责任编辑:莫奇 来源: 51CTO
相关推荐

2012-11-23 14:27:43

IBMdW

2023-03-01 15:52:30

2018-06-19 08:12:25

2018-06-22 10:18:52

2009-03-14 16:03:50

AccessMSSQL漏洞

2021-05-11 19:58:01

身份验证Code

2022-09-22 15:29:17

public-SDK应用开发

2014-09-01 09:49:24

github

2018-05-03 09:43:07

Linux命令传输文件

2013-04-03 12:53:23

Android开发shared_user

2022-09-05 07:32:46

mock数据Stream

2021-06-28 11:50:07

APIHTTP网络协议

2022-11-04 10:49:56

Linux文件

2010-01-29 09:08:57

Windows 7系统权限

2020-10-12 09:46:34

漏洞

2019-08-08 11:13:21

技术人晋升运营

2020-05-19 10:02:20

物联网数据分析IOT

2010-09-13 15:40:56

2020-04-29 10:35:45

远程工作员工CIO

2020-08-26 10:41:29

云计算投资云应用
点赞
收藏

51CTO技术栈公众号