如何托管前台和后台?

Back4app 全栈应用程序部署封面

在本教程中,我们将全面介绍如何托管应用程序的前台和后台。

为此,我们将在 Back4app 上托管一个全栈应用程序。我们将首先开发后台,然后开发前台,最后连接这两个组件。

目标

本文结束时,您将能够

前台和后台有什么区别?

后端和前端指的是构建现代网络和移动应用程序时的关注点分离。了解它们之间区别的最简单方法就是将冰山形象化。

后台与前台

前端(或客户端)是用户可以看到并与之交互的一切。前端有多种形式,如移动应用程序、网络应用程序、网络界面或其他任何类型的客户端。

该应用部分负责用户界面/用户体验、设计、动画、图形和其他媒体类型。客户端占项目工作的 20%,且不重复。

另一方面,后台(或服务器端)是用户看不到的一切。它是前端和数据库之间的桥梁。

它负责业务逻辑、后台任务、数据存储、扩展、第三方集成等。尽管用户不能直接与之交互,但它仍对应用程序的质量有很大影响。

它约占项目工作的 80%,通常包括用户管理、身份验证、加密等重复性任务。

在本教程中,您将免费学习如何在 Back4app 上部署前台和后台!继续阅读,了解如何部署后端和前端。

项目介绍

我准备了一个全栈应用程序来演示如何在 Back4app 上部署前端和后端。

该应用程序是一个简单的标记符博客。管理员可以添加、编辑和删除文章,而用户则可以阅读文章。

最终项目将是这样的

Back4app 全栈应用程序博客

如上所述,应用程序由两部分组成:前台和后台。如果我们将应用程序的架构可视化,它将看起来像这样:

Back4app 全栈应用程序架构

我们将把后端部署到Back4app,把前端应用部署到Back4app Containers。最后,我们将通过Parse SDK 连接这两个组件。

我建议你先学习这个应用程序,然后通过部署你的全栈应用程序来测试你的知识。

继续阅读,了解如何托管后台和前台。

如何托管后台?

在本节中,我们将处理应用程序的后台部分。

目标

  1. 创建 Back4app 应用程序
  2. 定义数据库类
  3. 设置数据库 ACL/CLP
  4. 填充数据库
  5. 启用管理应用程序

创建 Back4app 应用程序

您需要注册一个免费的 Back4app 帐户,以便了解更多信息。如果您尚未注册,请免费注册

要使用 Back4app,您首先需要创建一个应用程序。在 Back4app 上进行身份验证后,您将被重定向到应用程序视图。点击 “创建新应用程序 “按钮。

Back4app 创建应用程序

接下来,选择 “后台即服务”,因为我们要部署一个后台。

Back4app 后台即服务

为应用程序命名,选择 “NoSQL “数据库,然后点击 “创建”。

Back4app BaaS 配置

平台需要一点时间来准备一切(如数据库、扩展、备份、应用层)。在此期间,您可以喝杯咖啡休息一下。

应用程序准备就绪后,您将看到数据库资源管理器。

Back4app 数据库视图

定义数据库

在本节中,我们将学习数据库类。

我们只需要一个类,因为我们构建的是一个简单的应用程序。点击侧边栏上的 “创建一个类”,将其命名为 “文章“,其他内容保持默认,然后点击 “创建类并添加列”。

Back4app 创建数据库类

添加以下五列:

+-----------+--------------+----------------+----------+
| Data type | Name         | Default value  | Required |
+-----------+--------------+----------------+----------+
| String    | slug         | <leave blank>  | 1        |
+-----------+--------------+----------------+----------+
| String    | title        | <leave blank>  | 1        |
+-----------+--------------+----------------+----------+
| File      | cover        | <leave blank>  | 0        |
+-----------+--------------+----------------+----------+
| String    | shortContent | <leave blank>  | 1        |
+-----------+--------------+----------------+----------+
| String    | content      | <leave blank>  | 1        |
+-----------+--------------+----------------+----------+

确保为您想存储的其他数据添加列。

默认情况下,数据库类处于 “保护模式”。如果我们想在前端应用程序中与它们交互,就必须稍微修改一下类级权限(CLP)。单击屏幕顶部的锁图标,然后像下面这样修改 CLP:

Back4app Class CLP

阅读以下文章,了解有关Parse 安全性的更多信息。

最后,在数据库中添加一些样本文章。

如果您没有任何想法,请随时导入该数据库转储。要导入它,请单击屏幕右上方的更多选项,然后点击 “导入 > 类数据”,然后导入 JSON。

已填充 Back4app 数据库

很好,就是这样!

现在我们有了一些测试数据。

管理应用程序

目前,管理文章的唯一方法是通过 Back4app 数据库视图。这并不是最佳方式,因为您不想共享您的 Back4app 证书或将非技术人员添加到您的 Back4app 面板。

幸运的是,Back4app 为您的数据库模型提供了动态管理界面。要启用它,请选择侧边栏上的 “更多 > 管理应用程序”,然后点击 “启用管理应用程序”。

Back4app 启用管理应用程序

选择用户名、密码和管理应用程序子域。我选择

username:     admin
password:     verystrongpassword123
admin url:    https://fullstack.admin.back4app.com/

现在,您可以通过选定的管理 URL 访问管理面板。

打开一个新标签页并导航至管理面板。使用您的凭据登录并浏览界面。您可以创建文章、更新文章,然后删除文章。

Back4app 管理应用程序控制面板

查看文档,了解有关 Back4app 管理应用程序的更多信息。

我们已经成功创建了一个完全成熟的后台,无需任何代码。

如何托管前端?

在本节中,我们将介绍前端应用程序。

目标

  1. 设置本地开发环境
  2. Dockerize 应用程序
  3. 在本地测试 Docker 映像
  4. 将源代码推送到 GitHub
  5. 将应用程序部署到 Back4app 容器中

本地设置

首先分叉该版本库的所有分支,然后将分叉克隆到本地计算机:

$ git clone <fork_remote_git_url> --branch dummy
$ cd back4app-heroku-deploy && git branch -m master

我们克隆了虚拟分支,因为它不包含后台代码。我们将在下一节讨论后台代码。

接下来,安装项目的依赖项:

$ npm install

最后,启动开发服务器:

$ npm run dev

打开您最喜欢的网络浏览器,导航至http://localhost:3000。您应该可以看到博客索引页面。尝试点击一篇文章,看看是否会重定向到文章详细信息页面。

目前,文章详情页是硬编码。别担心,我们稍后会解决这个问题。

Dockerize

要将应用程序部署到 Back4app Containers,必须先对其进行 dockerize。

Dockerization 是将代码打包到容器中的过程,容器可以部署到任何地方。对应用程序进行 Docker 化的最简单方法是使用Dockerfile

Dockerfile

Dockerfile脚本包含创建 Docker 容器映像的说明。您可以使用该文件来定义环境、安装依赖项,并执行构建和运行应用程序所需的命令。

在项目根目录下创建一个Dockerfile,内容如下

# Dockerfile

FROM node:18-alpine

WORKDIR /app

COPY package*.json ./
RUN npm ci

COPY . .

RUN npm run build
RUN npm install -g next

EXPOSE 3000

CMD ["next", "start", "-p", "3000"]

Dockerfile基于node:18-alpine映像。它设置工作目录、处理依赖关系、复制项目并构建应用程序。

一旦应用程序构建完成,它就会暴露3000端口,并启动一个监听该端口的 Next.js 服务器。

要了解有关 Dockerfiles 的更多信息,请查看官方文档

.dockerignore

应尽量减小 Docker 镜像的大小。缩小 Docker 镜像大小的最简单方法是创建.dockerignore文件。通过该文件,你可以指定最终映像中应排除哪些文件和文件夹。

例如,你不想在镜像中包含 IDE 文件、构建文件、.git 文件或node_modules文件。

下面是一个.dockerignore文件的示例:

# .dockerignore

.idea/

/node_modules
/.next/
/out/
/build

.vercel

确保根据需要修改.dockerignore文件。

构建、运行、测试

在将 Docker 项目推送到云端之前,最好先在本地对其进行测试。测试Docker 文件的最简单方法是安装Docker Desktop

安装完成后,您就可以创建图像了:

$ docker build -t blog-frontend:1.0 .

列出图像,查看是否成功创建了图像:

$ docker images

REPOSITORY        TAG       IMAGE ID       CREATED             SIZE
blog-frontend     1.0       d361534a68da   2 minutes ago       1.08GB

使用刚刚构建的映像运行容器:

$ docker run -p 3000:3000 --name blog-frontend blog-frontend:1.0

打开您最喜欢的网络浏览器,导航至http://localhost:3000。您的应用程序应该就在那里!

要终止容器,请按键盘上的CTRL + c键。

推送到 GitHub

Back4pp Containers 与 GitHub 紧密集成。它提供了一个自动 CI/CD 系统,每次提交都会重新部署你的应用程序。要在下一节部署代码,必须先将更改推送到 VCS。

提交所有更改并将其推送到云端:

$ git add .
$ git commit -m "dockerized the application"
$ git push origin master

导航到 GitHub 代码库,确保Dockerfile在代码库中。

部署应用程序

您需要注册一个免费的Back4app 账户,以便跟进。如果您尚未注册,请免费注册

首先,进入 Back4app 面板,点击 “构建新应用程序”。

Back4app 创建应用程序

由于我们部署的是 docker 化应用程序,因此请选择 “容器即服务”。

Back4app Select CaaS

如果您是第一次使用 Back4app Containers,系统会要求您将 GitHub 账户与 Back4app 账户连接起来。确保启用对所有要部署的软件源的访问权限。

接下来,找到back4app-full-stack软件仓库,点击 “选择”。

Back4app 选择 GitHub 存储库

我们部署的应用程序不需要任何特殊配置。你只需提供一个描述性的 “应用程序名称”。我将使用back4app-full-stack来保持条理清晰。

最后,点击 “部署”。

Back4app 容器环境

Back4app Containers 需要几分钟时间来构建和部署您的 Docker 映像。成功部署后,应用程序的状态将变为 “就绪”。

要访问您的应用程序,请单击绿色 URL,如下图所示。

Back4app 成功部署

很好,您已经成功地在 Back4app Containers 中部署了一个虚拟前端应用程序。

如何连接前台和后台?

在本节中,我们将把前台连接到 Back4app 后台。

目标

  1. 安装 Parse SDK
  2. 配置 Parse SDK
  3. 获取数据(如使用ParseQuery)

安装 Parse SDK

首先,安装Parse SDK

$ npm install parse

配置 Parse SDK

要初始化 Parse SDK,您必须提供 Back4app 的 “应用程序 ID “和 “JavaScript 密钥”。要获取它们,请导航至您的 Back4app 应用程序,选择侧边栏上的 “应用程序设置 > 安全与密钥”。

由于我们不想在源代码中公开这些秘密,因此需要创建一个.env.local文件:

# .env.local

NEXT_PUBLIC_PARSE_APPLICATION_ID=<your_parse_app_id>
NEXT_PUBLIC_PARSE_JAVASCRIPT_KEY=<your_parse_js_key>

确保用实际值替换占位符。

初始化 Parse SDK

接下来,导航到您的providers.js,然后像这样初始化 Parse:

// src/app/providers.js

// ...

import Parse from "parse/dist/parse";

const PARSE_APPLICATION_ID = process.env.NEXT_PUBLIC_PARSE_APPLICATION_ID;
const PARSE_JAVASCRIPT_KEY = process.env.NEXT_PUBLIC_PARSE_JAVASCRIPT_KEY;
Parse.initialize(PARSE_APPLICATION_ID, PARSE_JAVASCRIPT_KEY);
Parse.serverURL = "https://parseapi.back4app.com/";

export function Providers({children}) {
    return (
        // ...
    );
}

为了能在所有视图中访问 Parse 实例,我们将使用 React 上下文。我们将使用React 上下文

新建一个名为context/parseContext.js的文件,并在其中粘贴以下代码:

// src/app/context/parseContext.js

"use client";

import {createContext} from "react";

const ParseContext = createContext();

export default ParseContext;

接下来,用ParseContext封装整个应用程序,并向其提供Parse实例:

// src/app/providers.js

// ...

import ParseContext from "@/app/context/parseContext";

export function Providers({children}) {
  return (
    <CacheProvider>
      <ColorModeScript initialColorMode={theme.config.initialColorMode} />
      <ChakraProvider theme={theme}>
        <ParseContext.Provider value={Parse}>
          {children}
        </ParseContext.Provider>
      </ChakraProvider>
    </CacheProvider>
  );
}

就是这样!现在我们可以使用useContext()钩子访问 Parse 实例了。

获取数据

我们要做的最后一件事是从后台获取数据。为此,我们将使用Parse.Query。该类基本上是基于 Parse 的数据库的 ORM。

首先,用下面的内容替换src/app/page.jsx

// src/app/page.jsx

"use client";

import NextLink from "next/link";
import {useContext, useEffect, useState} from "react";
import ParseContext from "@/app/context/parseContext";
import {Card, CardBody, Heading, Link, Spinner, Stack, Text} from "@chakra-ui/react";

export default function Home() {

  const parse = useContext(ParseContext);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState("");

  const [articles, setArticles] = useState([]);

  useEffect(() => {
    (async () => {
      try {
        const query = new parse.Query("Article");
        query.descending("createdAt");
        const articles = await query.find();
        setArticles(articles);
      } catch (error) {
        setError(error);
      } finally {
        setLoading(false);
      }
    })();
  }, [parse.Query]);

  if (loading) {
    return <Spinner size="lg"/>;
  }

  if (error) {
    return <Text color="red">{error}</Text>;
  }

  return (
    <>
      <Stack>
        {articles.map((article) => (
          <Card key={article.get("slug")}>
            <CardBody>
              <Stack>
                <Heading size="lg">
                  <Link as={NextLink} href={article.get("slug")}>
                    {article.get("title")}
                  </Link>
                </Heading>
                <Text>{article.get("shortContent")}</Text>
              </Stack>
            </CardBody>
          </Card>
        ))}
      </Stack>
    </>
  );
}
  1. 我们通过useContext()钩子获得了 Parse 实例。
  2. 我们创建了一些状态,包括加载出错文章
  3. 我们使用useEffect()钩子在页面打开时运行Parse.Query
  4. Parse.Query会获取按创建时间排序的所有文章。
  5. 我们修改了返回语句以呈现数据。

然后将src/app/[slug]/page.js替换为以下内容:

// src/app/[slug]/page.js

"use client";

import {formatDate} from "@/app/util/date-util";
import {useContext, useEffect, useState} from "react";
import ParseContext from "@/app/context/parseContext";
import {Card, CardBody, Heading, Image, Spinner, Stack, Text} from "@chakra-ui/react";
import ReactMarkdown from "react-markdown";
import ChakraUIRenderer from "chakra-ui-markdown-renderer";

export default function Article({params}) {

  const parse = useContext(ParseContext);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState("");

  const [article, setArticle] = useState(null);

  useEffect(() => {
    (async () => {
      try {
        const query = new parse.Query("Article");
        query.equalTo("slug", params.slug);
        const article = await query.first();
        if (!article) {
          setError("This article does not exist.");
        } else {
          setArticle(article);
        }
      } catch (error) {
        setError(error);
      } finally {
        setLoading(false);
      }
    })();
  }, [params.slug, parse.Query]);

  if (loading) {
    return <Spinner size="lg"/>;
  }

  if (error) {
    return <Text color="red">{error}</Text>;
  }

  return (
    <>
      {article && (
        <Stack>
          <Card>
            <CardBody>
              <Stack>
                <Heading as="h2" size="lg">{article.get("title")}</Heading>
                <Text>Posted on {formatDate(article.get("createdAt"))}</Text>
                {article.get("cover") && (
                  <Image 
                      src={article.get("cover").url()} 
                      alt={`${article.get("title")} cover`} 
                      borderRadius="lg"
                  />
                )}
                <ReactMarkdown 
                    components={ChakraUIRenderer()} 
                    children={article.get("content")} 
                    skipHtml
                />
              </Stack>
            </CardBody>
          </Card>
        </Stack>
      )}
    </>
  );
}

我们在上面的代码中使用了类似的概念。这两段代码的主要区别在于,我们获取的是一篇特定的文章,而不是这一段中的所有文章。

我们就大功告成了!继续在本地测试该项目:

$ next dev

确定一切正常后,将其推送到 VCS:

$ git add .
$ git commit -m "connected the frontend with the backend"
$ git push origin master

Back4app Containers 将自动根据最新更改重新部署您的应用程序。

结论

最后,我们成功地在 Back4app 上部署了一个全栈应用程序。通过这一过程,您获得了托管应用程序前端和后台的宝贵经验。现在,您部署自己的全栈应用程序应该不成问题了。

最终源代码可在back4app-full-stackrepo 上获得,你也知道了前端和后端托管在哪里。


Leave a reply

Your email address will not be published.