发布于 2026-01-06 3 阅读
0

使用 GitHub 作为内容管理系统

使用 GitHub 作为内容管理系统

自从我的网站经过全新改版重新上线以来,我添加了一些很棒的功能。其中一个我觉得值得分享的功能是我的作品集页面,因为它实际上是使用GitHub作为内容管理系统 (CMS) 的。

那么,让我们一起来详细分析一下我为什么要添加这个功能,为什么不使用其他服务,当然还有它的工作原理。

❓ 为什么

在重新设计我的网站时,我设定了一些目标。其中一个目标是保留与我当时现有网站类似的个人作品集页面,该页面会抓取我所有的GitHub代码库并将它们全部列出。

不过,我想改进一下这个页面,添加一些内容筛选功能。最好是那种快速、易用、几乎随时随地都能访问,而且最好是免费的方法。

☁️ 无头CMS

我知道我需要某种无头CMS来让我管理我想显示的内容,所以我进行了一些思考和研究。

我发现大多数人都乐于推荐其他无头CMS服务,例如StrapiSanityGraphCMS等等,这些服务确实能满足我的需求,为我提供一个无需重新部署即可管理和维护内容的平台。但它们大多也存在我不喜欢的相同问题。

弹力

试图让个人作品集网站的正常运行时间达到 99.999% 是否有点过头了?或许是吧。

我的网站宕机重要吗?不重要。但我喜欢像对待其他生产环境一样对待它,尽可能避免增加潜在的故障点。在这个例子中,我指的是为我的作品集页面提供数据的第三方服务。

如果第三方服务宕机,我的内容是否会通过某种缓存机制神奇地继续提供,直到服务恢复?还是根本就没有任何内容可供提供?

“但你是从 GitHub 获取数据,对吧?所以你仍然依赖于他们的数据。” 说得对,我的确如此。但是,相比内容管理系统(CMS),我更信任 GitHub 的正常运行时间和平台稳定性,而且添加故障保护机制也更容易,这样即使 GitHub 宕机,我们仍然可以提供内容(稍后会详细说明)。

价格

有些人可能会觉得我这样做很抠门,但我个人网站的另一个目标就是尽可能降低成本。截至目前,我的网站每年的运营成本仅为20美元。就这些。

怎么做到的?很简单。域名每年只需 20 美元,代码托管在 GitHub 上,然后部署到Vercel。就是这么便宜,而且我希望一直保持这个价格。

所以,无论很多服务看起来多么诱人,我都无法接受为其他服务付费。因此,我想要找到一种替代方案,它能满足我的需求,而且无需任何额外费用。

🔨 如何

如果您只想查看最终代码以了解其工作原理,请projects.ts前往我的网站 GitHub 存储库查看该文件。

简单来说,它的工作原理是这样的:通过GitHub 的主题功能,你可以筛选出你想显示和不想显示的内容。我给所有选定的仓库都添加了一个portfolio主题,这样这些仓库就会出现在我的作品集页面上。

要实现这个功能,我们需要两个关键要素:Next.jsGitHub API。此外,你还可以选择使用某种缓存工具,例如Upstash,来缓存数据,从而减少对 GitHub API 的请求次数。

正在获取存储库

首先,我们将设置一个基本getServerSideProps函数,该函数允许我们从服务器上获取存储库数据并将数据传递给客户端。

// portfolio.jsx
export async function getServerSideProps () {
    const response = await fetch('https://api.github.com/users/GITHUB_USERNAME/repos');
    const json = await response.json();
    return {
        props: {},
    };
};
Enter fullscreen mode Exit fullscreen mode

存储库筛选

在这里,我们可以添加自定义逻辑,根据 GitHub 返回的数据来筛选数据。在这个例子中,我们将过滤掉所有既没有指定portfolio主题又未被归档的仓库。

// portfolio.jsx
export async function getServerSideProps () {
    // ...
    const repositories = json.map((repo) => {
        if (!repo.topics.includes('portfolio')) return null;
        if (repo.archived) return null;
        return repo;
    })
    .filter((project) => project !== null);
    return {
        props: {
            repositories,
        }
    }
};
Enter fullscreen mode Exit fullscreen mode

GitHub 身份验证

接下来是一个可选步骤,我强烈建议您执行此步骤,以降低达到 GitHub API 速率限制的几率。

要完成此步骤,您首先需要创建一个 GitHub 个人访问令牌。您可以参考此处的官方指南

将新生成的访问令牌添加到您的.env文件中。

GITHUB_PAT=abc123
Enter fullscreen mode Exit fullscreen mode

添加此功能后,您可以更新 fetch 请求,将令牌添加到请求标头中。

// portfolio.jsx
export async function getServerSideProps () {
    const response = await fetch('https://api.github.com/users/GITHUB_USERNAME/repos', {
        headers: {
            authorization: `token ${process.env.GITHUB_PAT}`,
        },
    });
    // ...
};
Enter fullscreen mode Exit fullscreen mode

缓存

最后一步也是可选的,但有助于提升平台弹性和响应速度。简而言之,我们将使用某种超高速缓存数据库(例如 Redis)来存储首次请求后的数据,之后每次请求都会使用缓存的数据,而无需发出多个请求。

我的网站最终选择了Upstash,它免费提供一个 Redis 数据库。我建议按照他们的指南来设置你的第一个 Redis 数据库

数据库设置完成后,您现在应该可以REDIS_URL添加.env文件了。它应该类似于这样rediss://USERNAME:PASSWORD@HOST:PORT。如果没有用户名,也不用担心。

GITHUB_PAT=abc123
REDIS_URL=rediss://USERNAME:PASSWORD@HOST:PORT
Enter fullscreen mode Exit fullscreen mode

现在我们有了要访问的数据库,还需要一个客户端来访问它。有很多 Redis 客户端可供选择,包括 Upstash自带的客户端,但我个人更喜欢Upstash 的客户端,ioredis所以在这个例子中我会使用它,不过其他客户端应该也能正常工作。将其作为开发依赖项安装即可。

npm install --save-dev ioredis
Enter fullscreen mode Exit fullscreen mode

或者使用 Yarn

yarn add -D ioredis
Enter fullscreen mode Exit fullscreen mode

安装完成后,我们可以创建一个新的客户端实例来连接到我们的数据库。

// portfolio.jsx
export async function getServerSideProps () {
    const redis = new Redis(process.env.REDIS_URL);
    // ...
};
Enter fullscreen mode Exit fullscreen mode

最后,我们可以添加实际逻辑来检查缓存中是否已经有了我们需要的数据,如果没有,我们可以从 GitHub 获取最新的数据并将其存储在缓存中,然后再最终返回它。

// portfolio.jsx
export async function getServerSideProps () {
    // ...
    const cache = await redis.get('repositories');
    if (cache !== null)
        return {
            props: {
                repositories: cache,
            }
        }
    const repositories = ...
    redis.set('repositories', JSON.stringify(repositories));
    return {
        props: {
            repositories,
        }
    }
};
Enter fullscreen mode Exit fullscreen mode

✅ 结论

就这样,我们拥有了一个非常简单但又很强大的系统,它允许我们使用 GitHub 来管理网站上显示的内容,但又不完全依赖于 GitHub,因此如果 GitHub 端由于任何原因出现停机,我们仍然有缓存的数据。

// portfolio.jsx
export async function getServerSideProps () {
    const redis = new Redis(process.env.REDIS_URL);
    const cache = await redis.get('repositories');
    if (cache !== null)
        return {
            props: {
                repositories: cache,
            }
        }
    const response = await fetch('https://api.github.com/users/GITHUB_USERNAME/repos', {
        headers: {
            authorization: `token ${process.env.GITHUB_PAT}`,
        },
    });
    const json = await response.json();
    const repositories = json.map((repo) => {
        if (!repo.topics.includes('portfolio')) return null;
        if (repo.archived) return null;
        return repo;
    })
    .filter((project) => project !== null);
    redis.set('repositories', JSON.stringify(repositories));
    return {
        props: {
            repositories,
        }
    }
};
export default function Page({ repositories }) {
    return (
        <pre>
            {JSON.stringify(repositories, null, 4)}
        </pre>
    );
}
Enter fullscreen mode Exit fullscreen mode
文章来源:https://dev.to/nuro/using-github-as-a-cms-2n28