Transcription
是的。晚上好,各位。欢迎回到我们训练营的第三天,对于昨天的那个问题,我真的非常抱歉。由于目前我这里恶劣的天气,我们正在面临一个相当严重网络问题。所以,直到昨天,我们还在讨论数据库部分,并且我们刚刚开始创建集群。所以,我想,希望到目前为止,那部分已经完成了。现在我们将继续进行下一部分,即获取连接字符串并将连接字符串添加到您的后端。这是我们要做的下一件事。好的。所以,让我们快速完成它,今天我们将创建模式和其他东西。所以我希望我今天能写完大部分后端代码,因为已经是第三天了。我们还有第四天和第五天,我们需要进行部署,并且还需要讨论作业和其他事情。所以,让我们快速开始吧。我再次登录到我的网站。好的。请稍等片刻。是的。而且,我想资源已经与您共享了。如果还没有共享,很快就会与您共享。所以,所有的笔记都在同一个Canva白板上。您将收到一个单独的白板链接,或者我们将下载并以PDF格式共享。所以,我们将这样共享笔记。代码也已经共享了代码沙盒。它已经是公开的。所以,您可以看到视图。您可以过去看看。您可以查看端口,只是您无法编辑它。好的。所以,请稍等片刻,好的,正在登录网站,集群已经在上一节课中创建了。我们已经创建了集群。现在我想进入的下一件事是,我想向您展示如何确切地获取连接字符串,以及如何确切地将其连接到我的后端。好的。所以,您将在此处看到一个获取连接字符串的选项。好的。所以,您只需点击此按钮,然后您将获得选项。在第一步中,您将获得选择如何连接的选项。它会询问您MongoDB CLI。它将有Compass和其他选项。您可以选择Compass。好的。所以,现在如果您向下滚动一点,您将在此处看到一个连接字符串。好的。这是我这个集群的完整连接字符串,并且,连同集群一起,我想它是为我的应用程序准备的。好的。让我们进入集群本身。好的。我们不需要应用程序开发的连接字符串。我们将使用集群本身。所以,只需选择Compass。您有Shell、VS Code的MongoDB和TLS SQL2。我们不处理SQL数据库。我们处理NoSQL数据库。所以,我们将为此选项选择Compass。所以,您可以检查一下您是否安装了MongoDB Compass。如果没有,您可以安装它。但是,即使您没有安装,也没关系。我们可以继续进行。不必担心。所以,在底部,您将看到这个连接字符串。好的。这是连接我们的数据库与后端的关键部分。所以,我们必须使用它,而且,我想昨天我解释了这部分,当我们断开连接时。那是数据库密码。好的。所以,在创建您的帐户时,或者如果您还没有创建,您可以看到数据库访问按钮,您可以点击它。所以,将有一个用户和与该用户对应的密码。所以,您必须在这里使用该密码。好的。现在,在编码时,我将向您展示我的整个连接字符串。显然,它将包含数据库密码。不必担心。我为此目的创建了一个单独的集群。好的?所以我不能隐藏它。我必须展示它。所以,对您来说,只是不要分享它。好的。对您来说,只是将其保密。对您自己保密。对我来说,一旦会话结束,我就会完全清除它。我删除集群和数据库,所以我不必担心。所以,现在您已经获得了连接字符串,只需删除此处已写入的数据库密码,然后粘贴您自己的数据库密码。我告诉过您,您可以转到数据库访问。在数据库访问中,您将有一个选项,可以获取此数据库密码。好的。所以,现在这里有一个选项,您可以编辑密码,或者您可以做任何您想做的工作。所以,您可以从这里获取密码,其余的我将做的是,我将使用我已创建的数据库集群字符串,然后粘贴它。好的,好的。所以,这只是关于数据库的一个介绍,您如何进行,如何创建集群,以及在这种情况下您将如何确切地获取密码。现在,下一件事是,我们需要在我的编辑器中编写什么代码,以便我可以连接到我的后端。我可以将我的后端连接到我的数据库。好的。所以,这是这里的要点。所以,现在让我们转到代码部分,我们在这里已经创建了服务器。所以,下一部分是我的数据库与我的服务器的连接。好的。所以,在这种情况下,我将创建我的MongoDB连接。所以,您可以给它命名,您可以命名为connection,或者connectDB,无论您觉得最合适,您都可以使用。所以我现在使用connectDB,并且因为它将是一个异步操作。好的。所以,我将为此创建一个箭头函数。好的。所以,这是我的函数,函数名是connectDB,它是一个异步函数。当然,我将有一个try-catch块。我为什么需要一个try-catch块?因为我想在我的情况下进行异常处理。好的。所以,如果我在连接到我的数据库时遇到任何异常,在这种情况下,我需要一个catch块来处理该异常。所以,每当我遇到异常,每当我连接时遇到错误。所以,我将在相应的情况下进行console.error,并告诉我的用户MongoDB连接错误。现在,这个错误可能发生的所有可能情况是什么?所以,有一种可能的情况是,您使用的连接字符串是错误的。第二种可能的情况是,在连接字符串中,您没有添加您的数据库密码,那就是其中之一,第三种是您添加的数据库密码是错误的。好的。所以,有三种可能的情况。所以,如果您在连接到数据库时遇到错误,只需查看它,从这三者中调试。好的。现在,在try块中,我的try块中会是什么?我现在将使用我的密码。所以,con uri或URL,无论您想如何命名。现在,我直接添加URL,但是,但是很可能在下一节课中,在部署之前,我们还将看到如何确切地创建一个ENV文件,以及如何通过ENV2添加我们的连接字符串。好的。所以,这是我的数据库密码。抱歉,这是我的数据库连接字符串。所以,con uri等于已添加的整个字符串。它也包含密码。不必担心。我会在会话结束后将其清除。所以,即使您获得了密码,也没问题。但是,请尝试使用您自己的。好的。不要使用我的连接字符串。即使您能看到它,也没问题。但是,请尝试使用您自己的连接字符串。创建您自己的集群。做您自己的所有工作。好的。这将是您能做的最好的事情。好的。所以,这是我的连接字符串。现在,让我验证一下,让我创建一个await case,然后,让我看看我的条件字符串是否完成。好的。所以,mongus.connect是一个函数,它将我的MongoDB连接到我的后端。所以,在这种情况下,我定义了一个URL,我将把这个URL作为参数传递。好的。因为URL是这个锁的唯一访问权限。好的。所以,您需要这个。然后,我们需要定义另一件事。使用新的URL解析器也是必需的。我为什么需要URL解析器?因为这是一个连接字符串,当这个连接字符串回到您的数据库时,它将单独提取所有项目。所以,数据库密码单独,其他东西单独。所以,为此,我们需要一个数据库密码,抱歉,URL解析器,在这种情况下。好的。是的。所以,我们写的解析器拼写。所以,解析器,我们将它设置为true,以及我的新的URL解析器。我将做新的统一拓扑。好的。这是我将在这种情况下做的下一件事。所以,新的URL解析器和新的统一拓扑是我们将在这种情况下做的两件事。好的,好的。所以,这是我的连接。太好了。现在,在catch块中,我将添加另一件事。如果发生任何错误,我将退出。好的。所以,我将在此相应的情况下执行process.exit。好的。在这种情况下,需要process.exit,因为如果发生任何错误,我需要退出此连接过程,我不需要卡在这个连接过程中,所以,我现在将添加一个process.exit case。好的,好的。所以,有了这个,是的。所以,我还需要退出代码。在这种情况下,退出代码为1。如果发生任何连接错误,将显示一个错误,即连接错误,另一个我们将看到的是进程以代码1退出。所以,这是两种可能的情况。所以,让我检查一下。让我尝试运行我的服务器,看看一切是否正常。好的。所以,我将为此打开一个新的终端。所以,直到上次我们启动服务器时,它运行正常。让我们看看现在是否正常。好的。所以,npm start。将执行npm start,让我们看看。所以,是的,这意味着我的终端上没有显示任何错误,这意味着一切正常,并且连接没有问题,连接也正常。如果连接有问题,它会显示在屏幕上。好的。现在,现在,让我们进入下一部分。这是我的数据库,数据库连接已经成功完成。目前这里没有问题。现在,下一件事是,模型创建。好的。下一件事是模型创建。所以,我们将创建一个模型或模式。好的。在这种情况下,我们将同时创建模型和模式。所以,现在正如我所说的,我们还需要身份验证。我们还需要存储我的任务。所以,我们将创建两个不同的模型。一个是我的任务模型。另一个是我的用户模式模型。所以,这是我们将坚持的两个模型。所以,让我们先创建我的任务模型。所以,这将命名为task schema。好的。所以,我们首先创建模式,然后将其添加到我们的模型中。所以,new mongoose.Schema。所以,con taskSchema = new mongoose.Schema已经完成。好的。S应该是大写的。现在,在这个task schema中,我们将添加什么东西?所以,我们要添加的第一件事是标题本身。好的。所以,我正在创建的任务的标题是什么?我们需要什么属性?所以,在这种情况下,类型将是字符串。好的。所以,类型将是字符串。必需,我们将它设置为true。好的。而且,修剪。是的。如果我们想要,如果我们有一个非常长的标题,我们也可以修剪它。我们可以把它弄短一点。好的。在这之后,标题的下一件事是什么?所以,我的任务的状态。所以,它已完成还是未完成。所以,我们也需要那个。而且,完成部分将是布尔值格式,它可以是true,也可以是false。好的。所以,默认情况下,我也会添加一个默认值。默认情况下,我将我的值保留为false。好的。因为当您添加一个新任务时,默认情况下它未完成。所以,在这种情况下,我将false作为默认值添加到这里。然后,下一件事是创建时间戳,我们正在获取。所以,它是什么时候创建的,或者它是什么时候创建的。所以,我们也需要那个。而且,默认情况下,如果用户不添加,我们将将其保留为Date.now。所以,Date.now将获取当前的日期。好的。所以,这就是为什么我们将我的默认值保留为Date.now。现在,创建于,然后是更新于。下一部分是更新于,对于这种情况,类型也将是我的日期类型。好的。所以,类型将是我的日期类型,并且默认情况下,我将再次将其保留为Date.now。好的。默认情况下,我将将其保留为Date.now。所以,这是我的任务模式。如果您愿意,我也可以将其添加到笔记中。所以,当您查看笔记时,您可以回顾一下。所以,这是我的模式部分。好的。所以,这是我的第一个模式,这是我的任务模式,我可以这样命名。好的。是的。所以,模式,然后是我的任务模式。所以,模式,然后是我的任务模式。好的,模式和我的任务模式。我们将把它添加到这里。好的,所以,我们在模式中有两个值或两个字段,从标题,完成,更新于和更新于。好的。所以,这是我的测试模式。完成了。现在,让我们继续下一件事,那就是,在任务模式之后,我们需要一个用户模式。好的。所以,用户模式是下一件事。是的,这里还有一件事。所以我创建了任务模式,但是模型创建仍然是剩余的。所以,让我为此创建一个模型。所以,con task = mongoose.model,我将在此情况下传递任务。所以,我使用的模型名称是task,或者您也可以使用task2,比如task的复数。所以,我定义的名称是task schema。好的。现在,有了这个,我的模式就完成了。一分钟,关于连接字符串。是的。所以,在连接字符串中,我们还没有添加我们要创建的数据库的名称。所以,我们可以做的是,我们可以做斜杠,您可以添加一个任务,但由于我参加了多个训练营,我将将其命名为backend bootcamp。好的。因为我有很多数据库。是的。所以,backend bootcamp。好的。所以,task schema完成了,task model也创建了。现在,下一件事是什么?所以,正如您所知,身份验证部分也很重要。所以,我们现在需要创建一个用户模式。所以,对于用户模式,我们将使用用户名,或者,让我们也使用用户电子邮件。好的。如果您愿意,您可以选择用户名,但是,最好的部分是什么?如果用户不想提供他的电子邮件怎么办?在这种情况下,我们可以创建一个用户名,密码,第三件事将是创建于,它将是Date.now本身。所以,我们将在此情况下创建我的用户模式。与我们之前的情况相同。所以,如果您想尝试一下,您也可以在我写的时候,尝试写创建这个模式。所以,现在在这个用户模式中,我们要添加的第一件事是用户名,好的,用户名和属性。所以,在这种情况下,类型是字符串。好的。所以,在这种情况下,类型是字符串。必需,是的,它是必需的。必需设置为true,因为所有来到我们网站的用户,无论是在注册还是登录,都需要有用户名。这是默认的强制要求。您不能跳过它。所以,在此之后,下一件事是密码。好的。所以,我们将添加一个密码字段,它也将是字符串类型,必需也将设置为true。而且,您会看到,在这种情况下,我们没有创建任何默认值。但是,有一件事我们应该添加到用户名中,那就是我们创建的每个用户名都应该是唯一的。好的。这是其中一件事。所以,我们可以做的是,我们可以添加一个唯一的属性到这个用户名,或者,如果您想了解更多,就像主键一样。好的。所以,我们可以做的是,我们可以定义一个唯一的属性。好的。所以,unique将设置为true,而且,再次,trim也将设置为true。好的。所以,密码显然不需要设置为唯一,用户名我们想要它作为主键之类的。所以,在这种情况下,我们将把它定义为唯一的。好的。然后,创建于,它不是强制性的,但我们正在获取它,所以我们可以有一个创建时间戳。好的。所以,类型将是日期,而且,现在我将保留的默认值是Date.now。好的。Date.now将暂时保留。好的。所以,这是我的用户模式。现在,让我们快速创建我的用户模型。所以,con user = mongoose.model。好的。所以,con user = mongoose.model,模型名称是什么?我将其命名为user,然后是user schema。好的。所以,我们正在使用user schema。所以,有了这个,我们已经创建了我们的用户模式和模型。现在,让我复制它,并将其添加到我的笔记中。所以,task schema,然后这是user schema。好的。我希望到目前为止一切都清楚。所以,我们已经完成了数据库连接。我们已经为我的用户和我的任务创建了模式。所以,到目前为止,这是user schema完成,task schema完成,并且连接已经完成。这就是我们到目前为止所做的。所以,让我检查一下我的终端上是否有任何错误或任何闪烁的东西。如果我发现任何东西,我将先解决它,然后我们将继续。好的。好的。好的。所以,我定义了date。好的。所以,应该是Date.now,而不是Date,Now。这是我们犯的错误。好的。好的。是的。所以,它已经好了。它已经好了。好的。现在,我可以看到错误已经解决了。所以,我们可以继续了。好的。所以,我希望到目前为止一切都清楚,我们是如何创建模式,如何创建模型的。现在,下一件事是,我们将创建一个身份验证中间件。在此之前,让我向您解释我们将使用哪种身份验证。所以,我们将使用JWT身份验证。所以,我们将首先向您解释什么是JWT,以及为什么我们将使用JWT身份验证。好的。好的。所以,这是我的身份验证情况。所以,首先,如果用户是新的,好的,如果用户是新的,在这种情况下,我们要做的第一件事是注册。好的。所以,然后我们将为用户注册。这是我们要做的第一件事。所以,如果用户是新的,那么注册。如果用户不是新的。好的。它将是if。好的。所以,如果用户是新的,那么注册。如果用户不是新的,那么我们将直接登录。现在,让我们了解一下JWT在这种情况下是如何工作的。如果用户不是新的,那么登录。现在,关于JWT,JSON Web Token。所以,它实际上做什么?它实际上是创建一个令牌。好的。我们在这里谈论令牌。所以,会发生什么?我们不是在谈论注册情况。所以,对于注册情况,没有生成令牌,但是对于登录情况,好的,对于注册情况,新用户来了,用户名被添加,密码被添加,是的,我们还将对密码进行加密。所以,在此之后,当我们创建/signup或/register时,我将再次强调这一点。好的。所以,现在我正在谈论登录情况。好的。所以,每当用户登录时,好的,每当用户再次访问他的网站时,那么会发生什么?使用用户名或用户ID,会生成一个令牌。好的。所以,每当用户登录时,每当用户来到网站时,就会使用用户名或用户ID生成一个JWT令牌。好的。所以,它取决于我们,我们实际上发送到JWT的是什么。所以,它将定义或生成给定用户的用户令牌。现在,一旦令牌生成,然后接下来会发生什么?好的。一旦令牌生成,令牌就会存储在本地存储中。好的。所以,一旦令牌生成,该令牌就会存储到您的本地存储中,然后,对于您进行的下一次连续登录,您进行的下一次连续登录,您无需再次添加用户名和密码。好的。所以,现在有一种传统的登录方式,那就是一次又一次地,您访问网站的次数越多,您就一次又一次地添加用户名,您再次添加密码,然后您就进入了网站。但是在这种情况下,我们正在做的是,我们正在做的是,我们正在跳过那部分。好的。所以,还有一件事很重要,现在要强调的是,JWT有有效期。好的。JWT有有效期,或者我们可以,是的。所以,JWT令牌或JWT,无论您想如何称呼它。所以,JWT有有效期。所以,有效期将从1小时到您指定的任何小时。好的。从1小时到最多,它可以达到用户定义的案例。所以,现在会发生什么?您首先注册,在登录情况下,您来到网站,您添加了您的用户名。您添加了您的用户密码,使用用户名或用户ID,会生成一个令牌,并将其存储到您的本地存储中。现在,从您登录到1小时的时间,无论您进行多少次登录,或者无论您访问该网站多少次,您都不需要再次输入您的登录密码和用户名。好的。所以,您不必一次又一次地添加。所以,对于那段特定的时间,对于那段特定的时间,会话将通过令牌保持活动状态。所以,您不必再次添加密码和用户名。好的。这是我们JWT情况下的重要事项。好的。所以,直到令牌可用,就没有必要,让我连接起来。没有必要再次添加登录,用户名,用户名和密码。好的。这是这里的重要事项。所以,直到会话已结束,抱歉,直到令牌尚未过期。现在,在我们的情况下,我们将将其设置为1小时,但是,在您的情况下,您也可以将其设置为最大值。好的。您也可以将其设置为任何其他,更像是一个值,但是,在我们的情况下,我们将只设置为1小时,而不是更多。好的。所以,现在,直到1小时的有效期,您将能够毫无问题地进入网站,没有任何问题,没有任何登录凭据。1小时后会发生什么?1小时后,1小时后会发生什么?您的令牌会再次生成。您会再次生成您的令牌,然后,然后您将再次遵循相同的过程。好的。这就是JWT在这种情况下如何工作。好的。所以,请记住这一点,让我们现在编写JWT的代码。代码沙盒再次要求重新加载。请稍等片刻。让我们重新加载它。好的。好的。好的。所以,是的。所以,我希望令牌的创建令牌是清楚的。好的。所以,令牌将存储在您的本地存储中。所以,每当您再次访问网站时,它只会将您的令牌与您本地存储中已有的令牌进行匹配,然后,如果已进行身份验证,那么您就可以进入您的网站。如果它不正确,它将要求您提供用户凭据。好的。所以,是的,我还需要添加这一点。好的。所以,本地存储中的令牌与JWT再次生成的令牌进行匹配。好的。所以,您存储在本地存储中的一个令牌,以及通过使用您的用户ID再次生成的另一个令牌,它们都匹配,如果它们相同,就像它们正常工作一样,您可以进入。好的。现在,让我们为这种情况编写代码,或者JT中间件,JWT中间件。好的。好的。是的。所以,在这种情况下,我将定义我的con O,因为它负责我的身份验证请求响应和下一个,现在请求响应和下一个。所以,在这个JT中间件中,我们要做的第一件事是,令牌con token = request.head,或者request.header authorization。所以,这是一个中间件,它将比较令牌。好的。令牌的生成,我们稍后将编写代码。好的。替换。所以,每次我们在头部发送身份验证B。好的。所以,如果您对后端有所了解,您就会理解B是什么。好的。因为如果我现在开始解释B,它将占用我很多时间。好的。所以,我正在检查,我收到的请求,在这种情况下,我是否收到令牌。如果我收到令牌。所以,为此,我需要定义一个if条件,如果令牌可用。如果令牌可用。好的,我将把它写在一行。如果令牌不可用。第一种情况是令牌不可用,因为我添加了一个非操作。然后,我将执行return res.status 401,不是4012,而是确切的401。我想我添加了一个请求,抱歉,状态码为401。它到底是什么意思?401表示未经授权。好的。所以,我正在检查我的令牌是否存在。如果我的令牌在我的API调用头部存在,那么我就被授权了。如果我的令牌不可用,这意味着我的令牌已过期,或者根本没有生成令牌。所以,有两种可能的情况。所以,现在我假设我的令牌已过期。所以,401表示未经授权,我将无法对任何路由进行任何API调用。好的,好的。所以,这是rest.status 401,我们将发送一个JSON响应,其中包含一个错误。好的。所以,什么错误是SS denied。SS denied。这意味着您无法访问该特定端点。所以,JSON之前会有一个点。好的。正确。好的。所以,这是第一种情况。如果令牌不可用,这意味着令牌已过期,或者令牌从一开始就没有生成。现在,下一件事是我的try块,我将在其中解码令牌和其他所有东西。所以,con decode = JWT.verify first。现在,第一个检查是令牌是否可用。现在,第二个检查是,即使令牌可用,令牌是否有效。下一件事是,所以,令牌,所以,如果令牌存在,那么我必须检查令牌是否有效。好的。所以,它将是secret key。好的。现在,在这种情况下,我们正在生成,我们正在检查令牌是否有效。如果有效,那么我们将执行request.body.decode,或者request.user = decode。所以,我们将它添加到我的用户中,然后我们将继续我的下一个操作。现在,我定义了一个try,我还需要定义一个catch,它将处理我在检查令牌或任何其他事情时遇到的错误。好的。所以,如果在此身份验证过程中发生任何错误,我将假设这是401错误,即您未经授权。好的。所以,我已经添加了一个检查,在顶部,以检查令牌是否已发送给我。现在,我添加的另一件事是,我添加了一个catch块来检查是否有错误,并且在身份验证过程中,在try块中,如果发生任何错误,那么我假设令牌无效。好的。这就是我假设的。所以,401。好的。所以,request.status。这将是response.status,而不是request,因为我们现在正在做响应。所以,response.status,然后,我们将发送一个JSON。我们将发送一个JSON,并告诉我的用户无效令牌。好的。无效令牌。所以,这就是我将发送给我的用户的东西。好的。所以,这是我的身份验证中间件,这是我的身份验证中间件,其中我正在获取令牌。所以,每当我命中任何端点时,我都必须将我的身份验证Beer与该端点一起作为头部添加,否则我将无法访问该端点。这就是这里的关键。好的?因为每个试图访问该端点的用户,他或她都应该已经被授权。好的?所以,如果没有令牌,那么您将无法继续。您将直接获得SS denied。如果存在令牌,但您仍然无法访问,那么这意味着您的令牌无效。所以,这是我们在此情况下涵盖的两种可能情况。好的,好的。所以,我的中间件已经完成了。现在,下一件事是,我将创建一个用户登录路由。好的。所以,现在这是我将要创建的第一个路由,我希望到目前为止没有疑问。我花时间解释了每一个概念。所以,如果有任何疑问,我们将尝试。好的。所以,请,请,请仔细阅读每一行,一切都清楚。好的。一切都写了都有原因。没有东西是凭空写出来的。好的。所以,现在,让我们做一件事。让我们创建我的登录路由,然后我们可以继续。好的。所以,我们需要一个登录路由。我们需要一个注册路由,我们需要一个任务,我们还需要很多路由。好的。在这种情况下。所以,我将创建一个登录路由,而且,一件事,注册路由将是您的家庭作业。我将添加一个注册路由,但是,直到明天的会话,而不是之前。所以,尝试创建一个注册路由。明天将添加一个注册路由,但不是今天。所以,今天,从今天到明天,您有时间,只需思考一下如何根据我目前正在创建的路由来创建注册路由。好的。所以,这是我的第一个路由,app.first,第一个路由将是/login或signin。所以我将其命名为login,这是一个异步函数。好的。在这种情况下,它将有请求响应和然后打印。好的,好的。为什么我们写app.post?为什么我们写app.post?因为登录是一个post方法。好的。每当用户尝试登录时,它将是后端的一个post方法。我已经向您解释了get、post、put、batch、delete。所以,我希望您对此没有疑问。好的。第二天我们已经涵盖了。所以,清楚地不应该有任何疑问,为什么我们使用post在这种情况下。为什么我们不使用get或其他东西。显然,get、patch和put不适合它。您只有一个选择,那就是post。好的。现在,对于登录情况,我需要两件事。两件事是什么?我们需要用户名,我们需要密码。各位,还有一件事我想强调的是,当您进行注册时,当您进行注册路由时,当您完成它时,请尝试使用bcrypt,好的?因为您需要哈希您正在使用的密码。所以,为此,您需要一个bcrypt。如果您无法做到,请不要担心,没问题。我将添加代码。但是,如果您自己尝试,会更好。所以,尝试访问文档。尝试自己创建API。这将是更好和更容易的。而且,请不要使用AI,这对您来说会更好,因为您将学到一些新东西。好的。所以,我将用户名和密码作为输入。好的。所以,con user = 我已经获取了用户名和密码,我将检查用户是否存在。该特定用户是否存在。好的。所以,我们创建的模式或模型是user model。对吗?哦,是的,user model。所以,我将在我的user model中检查,user.findOne,因为为什么我们做findOne?为什么我们做findOne?我清楚地告诉您,我们有用户名,并且用户名设置为唯一。这意味着只能存在一个用户名。好的。所以,没有用户名的重复。没有两个相同的用户名,只有一个用户名可以存在,具有特定的名称。好的。所以,这就是为什么我们做findOne。所以,user.findOne,我们正在查找该用户。现在,我们根据什么进行搜索?我们根据什么进行搜索?我们根据用户名进行搜索。好的。我们在这种情况下发送一个用户名,我们正在搜索该特定用户是否存在。如果,如果,如果用户首先不执行注册情况怎么办?注册有点被跳过,他们直接进入登录,这不是您应该做的最佳情况。所以,首先,我们将验证用户名是否已存在。好的。用户名是否存在。如果用户名本身不存在,那么检查密码有什么意义?好的。所以,这是我们添加的第一个检查。现在,在这种情况下,我正在检查我的用户名是否不存在。好的。好的。好的。所以,在这种情况下,我将检查我的用户名是否不存在,或者,好的。所以,如果不存在该特定用户名的用户,那么我将执行return res.status,再次401,即未经授权,或者您目前不允许进入网站。好的。我们可以发送什么消息?在这种情况下,我们可以发送一个无效的凭据消息。好的。所以,对于用户,如果他们在我们的数据库中没有用户名,则为无效凭据。如果用户存在,那么我将获取令牌。好的。我将获取JSON.sign令牌,而且,是的。所以,现在,在这种情况下,我正在生成我的令牌。所以,ID。所以,我使用我数据库中的用户ID来定义它。所有创建的用户,他们在此情况下都有一个用户ID,以及此特定情况的密钥。好的。现在,正如我所说的,我还需要添加XY。好的。我还需要添加XY。所以,我将添加的下一件事是expires in 1H,即在这种情况下生成的令牌应该在1小时的时间范围内过期。所以,它不应该存在超过1小时,一旦达到1小时,它将被删除,或者它将被移除。好的。所以,在这种情况下,我将执行response.json,我将在这种情况下将我的令牌作为响应发送。好的。每当我登录时,我将生成一个令牌,并在此情况下发送一个令牌的响应。好的。太好了。有了这个,我的登录路由就完成了。我的登录路由完成了。再次,注册路由是您的部分。我将在此处添加一个注册路由,您可以自己编写代码。好的。无需与我分享。我猜会有很多疑问,如何分享。无需与我分享。这只是为了您的练习。尝试自己制作。如果您没有完成,没问题。我将从我这边添加代码。好的。所以,登录完成了。下一件事我们应该做什么?所以,下一件事我们应该做的可能是,我们应该添加一个get操作来获取任务。好的。我们应该在此情况下获取一个任务。所以,我们首先将执行一个获取任务的情况,然后是创建任务的情况。好的。所以,我们将执行获取操作。我们将执行创建操作。我们还将执行更新操作。所以,在这种情况下,由于我们正在进行获取操作,所以它将是app.get,而不是app.post。好的。如果我们正在创建它,那么它将是app.post async request from response。好的,好的。所以,由于我们正在获取,我们将做的是,我们将获取数据。我们将从缓存中获取它。好的。所以,让我们做一件事。让我们创建一个缓存案例。好的。所以,在顶部,我将创建一个缓存。所以,每次您获取数据时,它都会存储在缓存中。好的。所以,con cache,您可以将其定义为任何您想要的名字。所以,con cache = minus that equal to。好的。所以,什么是缓存?我希望您对此有所了解。在这种情况下,我们正在使用node cache本身。没有什么不同。我们正在使用node cache本身。SDTL,我们还没有安装node cacher,对吗?所以,我们将安装它,我们需要它,所以我们将它命名为node caching。好的。所以,这是我的node cacher,安装这个node caching并调用它。好的。所以,con,您可以命名任何东西。所以我在这里将其命名为node cache,所以我将执行node caches = require('node-cache')。好的。反引号。所以,它将是node-cache。我们为什么在这种情况下添加缓存?因为,显然,您不希望每次都从源头获取数据。有时,缓存也会为您工作。所以,为了节省调用次数,我们正在做这个缓存工作。好的。好的。好的。所以,缓存完成了。现在,我将再次从缓存中获取我的任务,而不是从源头获取。好的。所以,所以,在这种情况下,我将创建一个con,现在我们实际获取什么?我们正在获取数据,并且我们正在从缓存中获取它。所以,我们将生成一个缓存键,c a c h e f。我认为这可能是您第一次接触。好的。不用担心。您可以导航它。所以,request,好的。所以,我们正在做request,但是我们是根据用户ID存储的。所以,将有多个用户,他们的数据将被存储。所以,我们是根据那个做的。还有一件事,一件事,这是一个符号。好的。太好了。用户名,user = do user ID all。好的。太好了。所以,现在,我们将这样创建缓存键。现在,使用缓存键,我们必须获取它。所以,cash a task = 现在,缓存已经创建了。现在,下一件事是什么?我们必须获取。所以,cash.get,我们将在此情况下发送缓存键。好的。首先,缓存键已生成,然后我们从缓存中获取任务,我们正在执行cache key,但是我们无法访问此持有者后面的测试服务器。好的。没问题,我们会解决的,这没问题,我们可以稍后查看。好的。所以,cache key已经完成了。好的。下一件事是什么?下一件事是什么?我们可以做什么?在这种情况下。所以,我们已经获取了它。我们必须检查缓存任务中是否有任何数据。好的。任务。好的。所以,我们正在搜索,是否有任何数据。看。好的。C A C H E task。好的。是的。所以,我们正在检查缓存任务中是否有任何数据。如果没有数据,那么我们将返回test.json,或者,让我们也做一个状态码,但我们将直接发送响应JSON。好的。好的。所以,我们可以做的是,所以,如果您的数据库中不存在任何任务,那么就没有错误发生。所以,而不是返回任何错误,我们将直接检查缓存数据是否存在,然后我们将发送该缓存数据。如果数据不存在,我们将不返回它。任务。好的。所以,如果cas task return JSON cach,是的,是的,好的,好的。所以,如果不存在数据,那么我们将不返回它。如果存在数据,那么我们将直接将其返回给用户。好的。然后,下一件事是,我们将做cache.set。所以,我们将设置它。我们将再次获取一些新的数据。所以,我们将做cache,task。好的。好的。等等,等等。所以,这是第一种情况。所以,我们得到了数据,然后,我们可以做什么?如果我的数据库中有新的更新数据怎么办?好的。如果我的数据库中有新的更新数据,在这种情况下,我必须获取它,从源头获取它。所以,让我在这里做。task = 所以,con task = await task task.find,我们将根据用户ID进行查找,在这种情况下,我们正在获取用户ID,从request。
点用户点ID,好的,那么如果缓存尚未更新,而我的后端数据库中有一些更新呢?在这种情况下,我需要将其获取上来,然后我将设置这个新数据。所以缓存点设置一个键。我之前设置的是旧数据本身。这是一种我犯过的错误。没有新数据,更新将无法实现,或者没有意义。所以你一直在用最后更新的数据更新,或者你一直在用旧数据更新。这并不是你能做的最好的事情。然后我们将执行 rest.JSON,在这种情况下,我们将执行类。好的,没问题。好的,所以如果你的缓存中有数据,那么在这种情况下会有一个响应,即使没有数据,或者即使有数据,在这种情况下也会有一个响应。所以会有两个响应,一个来自缓存,一个直接来自你的数据库。好的,没问题。所以这是我获取任务的情况。现在让我创建一个另一种情况,即发布任务或创建新任务,然后我将为你增加一个挑战,那就是根据ID获取任务。这将是我接下来要添加的内容。好的。是的。好的。所以,让我们快速完成发布任务。是创建新任务。好的。所以这将是 app.post。为什么是 app.post?因为我们正在进行添加任务的新操作。好的。所以任务点同步请求响应。好的。好的。同步就是同步。好的。我认为在这种特定情况下,请求逗号响应。是的。所以现在我们需要一件事,或者我们需要什么?我们需要我的任务标题。其他东西可以设置为默认值,但唯一强制的是我们需要一个任务。好的。所以现在我们可以做另一部分,那就是我们收到的数据的结构。如果需要,我们可以对其进行验证。我们可以将其发送到一个不同的验证函数,然后我们可以对其进行验证,并检查我们收到的任务或我们收到的结构是否正确。所以这是其中一件事。所以,我们将为此创建一个验证器。所以,在顶部,让我们在连接本身之前创建一个验证器,或者在用户之后。是的。所以我们可以在这里这样做。我将它命名为验证器。好的。所以,我们在这个验证器中到底要检查什么?所以,让我们写下来。好的。验证任务等于好的。所以这是我的任务,验证任务等于我将处理每个项目。所以我的第一个项目是 body title。好的。我将检查我收到的标题是否是字符串形式。以及它是否为空。好的。我正在检查这两件事。好的。我还在修剪它,以及修剪操作。我接下来检查什么?是长度。所以如果长度,我想要一个最小长度。好的。我想要一个最小长度为三。所以任务的最小长度应该是三。它应该是字符串。它不应该是空的。我将修剪掉它,如果任务中有任何额外的空格。好的,我将修剪掉它。这是第一种情况。现在下一个验证我将进行。我将检查我的 completed 是否为布尔值。好的。我希望我的 completed 是布尔值,因为我正在接受布尔输入。所以在这种情况下,我希望我的 completed 在这种特定情况下是布尔值。所以其他输入将不被允许,只有布尔值应该在这种特定情况下被允许。所以这是我的布尔情况。现在在 post 中,我将添加这个验证器,因为我将直接将我收到的整个请求发送到我的验证器。所以验证验证任务。好的。所以验证任务已添加。为什么我好的?缺少逗号。好的。所以,逗号验证任务,然后逗号异步请求响应。好的。所以,如果我们没有在这种情况下创建验证任务。所以我们必须在这里添加那些验证,而我不想这样做。所以我会直接检查我收到的请求中是否有任何错误。所以验证任务的添加。好的。所以,如果我收到任何错误不等于,让我们把它变空。如果我没有收到任何错误,在这种情况下,我将返回状态码 400 好的结果状态码 400 只是匹配 400 状态码的含义,好的,我希望你可以去那里看看,我将发送一个错误,好的,那么我们可以发送什么错误?我们可以直接发送我们收到的错误,因为我们将收到一个数组形式的响应。所以我们将直接以数组形式发送它,在这种特定情况下。现在完成了,我们的验证任务完成了。现在,如果我的验证任务完成了,那么我将创建我的新任务。所以 const task 等于 new task,我将在此情况下发送我的 request.body,并 await fetch for a task.save task.save 在这种特定情况下。所以新任务已创建,新任务已添加。一旦任务添加完毕,我将发送一个状态码,我必须发送一个 201 的状态码。所以 201 是表示新任务或新资源已创建。好的,没问题。所以这一个是我 post 请求的情况。我希望它很清楚。我们进行了 get 请求。我们进行了登录。我们进行了 post 请求。现在还有一件事没做。是什么?剩下的是我的注册。还有另一件事是让你做的,那就是按 ID 获取元素,或者按 ID 获取特定任务。所以你也要创建那个。我将从我这边添加代码,但只是创建它。好的。不需要提交。不需要提交。按 ID 获取任务,按 ID 获取任务,这是你接下来要做的。其余的将在下一节完成。在此之前,请继续浏览,回顾一下,如果你有任何疑问,请在聊天中添加。好的,我知道,所以我们稍后会尝试遵循这一点。好的。是的。好的,还有一件事,正如你在这个讲座的这一点上所分享的,请标记你的出勤,不要遗漏,任何你想到的疑问,我们将尝试澄清。所以,由于一些问题,我们以这种方式进行直播。所以我们已经因为这些问题浪费了两天。所以为什么我们不改变直播方式,这样你就不会再遇到同样的问题了。好的,各位。所以,请完成到这一点,请仔细阅读。我将分享所有必需的资源,我们将在明天再次见面,我们将完成它。我们将部署我们的应用程序,然后我们将看看如何测试它。好的。好的,各位,没问题。与你们的交流很愉快。我们明天同一时间再见,在此之前,再见,晚安。