用sail .js构建一个实时聊天应用

    如果你是一个目前使用Django、Laravel或Rails等框架的开发人员,你可能听说过Node.js。你可能已经在你的项目中使用了一个流行的前端库,比如Angular或React。到目前为止,您应该考虑完全切换到基于Node.js的服务器技术。

    然而,最大的问题是从哪里开始。今天,JavaScript世界在过去几年中以令人难以置信的速度发展,而且似乎还在不断扩大。

    如果您害怕失去在Node领域辛苦积累的编程经验,不要害怕,就像我们一样<一个href="https://sailsjs.com/">Sails.js

    js是一个实时MVC框架,旨在帮助开发人员在短时间内构建生产就绪的企业级Node.js应用程序。js是一个纯JavaScript解决方案,支持多个数据库(同时)和多种前端技术。如果您是一名Rails开发人员,您将很高兴了解到这一点<一个href="https://twitter.com/mikermcneil">麦克。麦克内尔js的创始人,是受到Rails的启发。你会发现Rails和sail .js项目之间有很多相似之处。

    在本文中,我将通过向您展示如何构建一个简单的、用户友好的聊天应用程序,教你sail .js的基础知识。sailschat项目的完整源代码可以在这里找到<一个href="https://github.com/brandiqa/sp-sails-chat">GitHub回购

    <我mg decoding="async" src="https://uploads.sitepoint.com/wp-content/uploads/2018/01/151665711301-sails-chat-app.png" alt="风帆聊天应用"loading="lazy">

    先决条件

    在开始之前,您至少需要有使用MVC架构开发应用程序的经验。本教程适用于中级开发人员。你还需要至少在以下方面有一个基本的基础:

    为了使它对每个人都实用和公平,本教程将使用默认安装在新sail .js项目中的核心库。这里不涉及与React、Vue或Angular等现代前端库的集成。但是,我强烈建议您在本文之后研究一下它们。此外,我们不会进行数据库集成。相反,我们将使用默认的、本地磁盘的、基于文件的数据库进行开发和测试。

    项目计划

    本教程的目标是向您展示如何构建类似于<一个href="https://slack.com/">松弛,<一个href="https://gitter.im/">git或<一个href="https://discordapp.com/">必威体育手机版登录

    不是真的!我们投入了大量的时间和汗水去创造这些出色的平台。目前开发的功能数量相当庞大。

    相反,我们将构建一个聊天应用程序的最小可行产品版本,它包括:

    • 单人聊天室
    • 基本身份验证(<一个href="//www.shaoxingby.com/what-is-passwordless-authentication/">无密码
    • 配置文件更新。

    我添加了概要文件特性作为额外的奖励,以涵盖更多关于sail .js特性的内容。

    安装Sails.js

    在开始安装sail .js之前,我们首先需要设置一个合适的Node.js环境。在撰写本文时,目前可用的最新稳定版本是v0.12.14。js v1.0.0也可用,但目前处于测试阶段,不建议用于生产环境。

    我能访问的Node的最新稳定版本是v8.9.4。不幸的是,Sails.js v0.12不能与当前最新的LTS正常工作。但是,我已经用Node v.7.10进行了测试,发现一切都很顺利。这仍然很好,因为我们可以在代码中使用一些新的ES8语法。

    作为JavaScript开发人员,您会意识到只使用一个版本的Node.js是不够的。因此,我建议使用<一个href="//www.shaoxingby.com/quick-tip-multiple-versions-node-nvm/">nvm工具轻松管理多个版本的Node.js和NPM。如果你还没有这样做,只要清除你现有的Node.js安装,然后安装nvm来帮助你管理多个版本的Node.js。

    下面是安装Node v7和Sails.js的基本说明:

    #安装最新版本的Node v7 LTSnvm<年代p一个n class="token function">安装v7<年代p一个n class="token comment">#将节点v7设置为默认值nvm违约<年代p一个n class="token builtin class-name">别名v7<年代p一个n class="token comment">#安装Sails.js Globalnpm安装- g帆

    如果你有一个良好的网络连接,这应该只需要几分钟或更少的时间。现在让我们继续使用Sails generator命令创建我们的新应用程序:

    #进入项目文件夹cd项目<年代p一个n class="token comment">#生成新应用风帆生成新的聊天应用程序<年代p一个n class="token comment">#等待安装完成,然后导航到项目文件夹cd聊天软件<年代p一个n class="token comment">#启动应用程序帆抬起

    应用程序启动需要几秒钟的时间。您需要手动打开该urlhttp://localhost:1337在浏览器中查看新创建的web应用程序。

    <我mg decoding="async" src="https://uploads.sitepoint.com/wp-content/uploads/2018/01/151665711902-new-sails-app.png" alt="帆抬起"loading="lazy">

    看到这一点,我们确认了我们有一个运行中的项目,没有错误,我们可以开始工作了。要停止项目,只需按一下控制+c在总站。使用您最喜欢的代码编辑器(我使用Atom)检查生成的项目结构。以下是你应该注意的主要文件夹:

    • api:控制器、模型、服务和策略(权限)
    • 资产:图片,字体,JS, CSS, Less, Sass等
    • 配置:项目配置,例如数据库,路由,凭据,地区,安全等。
    • node_modules:已安装的NPM包
    • 任务:用于编译和注入资产的Grunt配置脚本和管道脚本
    • 的观点:查看页面-例如,EJS, Jade或任何你喜欢的模板引擎
    • .tmp:在开发模式下,由Sails用于构建和服务项目的临时文件夹。

    在我们继续之前,我们需要做几件事:

    • 更新EJS包.中列出的EJS 2.3.4package.json,您需要立即将其更改为2.5.5进行更新。它包含一个严重的安全漏洞。在更改版本号之后,执行npm install来执行更新。
    • 热重载.我建议你安装<一个href="https://github.com/sgress454/sails-hook-autoreload">sails-hook-autoreload这不是一个完美的解决方案,但会使开发更容易。要为当前版本的sail .js安装它,请执行以下命令:
    npm安装帆-钩autoreload@for帆- 0.12——保存

    安装前端依赖项

    在本教程中,我们将花费尽可能少的时间构建UI。任何你熟悉的CSS框架都可以。在本教程中,我将使用<一个href="https://semantic-ui.com/">语义界面CSS图书馆。

    js没有关于如何安装CSS库的具体指南。有三种或更多的方法可以做到这一点。让我们分别看看。

    1.手动下载

    你可以自己下载CSS文件和JS脚本,以及它们的依赖关系。下载后,将文件放在资产文件夹中。

    我不喜欢用这种方法,
    因为它需要手动工作来保持文件更新。我喜欢自动完成任务。

    2.使用鲍尔

    此方法要求您创建一个名为.bowerrc在你的项目的根源。粘贴以下代码片段:

    “目录”“资产/供应商”

    这将指示鲍尔安装到资产/供应商文件夹,而不是默认的bower_components文件夹中。接下来,全局安装Bower,并在本地使用Bower安装你的前端依赖项:

    #通过npm-全局安装bowernpm安装- g鲍尔<年代p一个n class="token comment">#创建凉亭。Json文件,接受默认答案(除了选择y private)鲍尔init<年代p一个n class="token comment">#通过bower安装semantic-ui鲍尔<年代p一个n class="token function">安装语义用户界面——保存<年代p一个n class="token comment">#安装jsrender鲍尔<年代p一个n class="token function">安装jsrender——保存

    我会解释的目的jsrender以后。我认为最好一次性完成安装依赖项的任务。您应该注意,jQuery也已安装,因为它是语义用户界面

    安装后,更新资产/风格/ importer.less要包括这一行:

    @ import“. . /供应商/语义/ dist / semantic.css '

    中包含JavaScript依赖项任务/ pipeline.js

    varjsFilesToInject<年代p一个n class="token operator">=//加载帆。我o before everything else“js /依赖/ sails.io.js”//供应商依赖关系“供应商/ jquery / dist / jquery.js”“供应商/语义/ dist / semantic.js”“供应商/ jsrender / jsrender.js”// jQuery或Angular等依赖项被引入这里“js /依赖/ * * / * . js”//所有客户端JS文件//将在这里注入,没有特定的顺序。“js / * * / * . js”

    当我们奔跑帆抬起,则会自动注入JavaScript文件视图/ layout.ejspipeline.js指令。当前的咕哝着说setup将负责为我们注入CSS依赖项。

    重要的是:加上这个词供应商.gitignore文件。我们不希望在存储库中保存供应商依赖关系。

    3.使用npm + grunt.copy

    第三种方法需要花费更多的精力来设置,但是会导致占用更少的空间。使用npm安装依赖项,如下所示:

    npm安装Semantic-ui-css jsrender——保存

    jQuery将自动安装,因为它也被列为依赖项semantic-ui-css.接下来我们需要放入代码任务/ config / copy.js.这段代码将指示Grunt复制所需的JS和CSS文件node_modules资产/供应商文件夹给我们。整个文件应该是这样的:

    模块<年代p一个n class="token punctuation">.出口函数咕哝着说咕哝着说<年代p一个n class="token punctuation">.配置“复制”dev<年代p一个n class="token operator">:文件<年代p一个n class="token operator">:扩大<年代p一个n class="token operator">:真正的慢性消耗病<年代p一个n class="token operator">:”。/资产src<年代p一个n class="token operator">:“* * / * !(咖啡|更少)桌子<年代p一个n class="token operator">:“.tmp /公共”/ /复制JQuery扩大<年代p一个n class="token operator">:真正的慢性消耗病<年代p一个n class="token operator">:“。/ node_modules / jquery / dist /”src<年代p一个n class="token operator">:“jquery.min.js”桌子<年代p一个n class="token operator">:”。/资产/供应商/ jquery”/ /复制jsrender扩大<年代p一个n class="token operator">:真正的慢性消耗病<年代p一个n class="token operator">:“。/ node_modules / jsrender /”src<年代p一个n class="token operator">:“jsrender.js”桌子<年代p一个n class="token operator">:”。/资产/供应商/ jsrender”//复制semantic-ui CSS和JS文件扩大<年代p一个n class="token operator">:真正的慢性消耗病<年代p一个n class="token operator">:“。/ node_modules / semantic-ui-css /”src<年代p一个n class="token operator">:“semantic.css”“semantic.js”桌子<年代p一个n class="token operator">:”。/资产/供应商/语义用户界面的//复制语义ui图标字体扩大<年代p一个n class="token operator">:真正的慢性消耗病<年代p一个n class="token operator">:”。/ node_modules / semantic-ui-css /主题”src<年代p一个n class="token operator">:“* *”。“* * / * *”。桌子<年代p一个n class="token operator">:”。/资产/供应商/语义用户界面/主题构建<年代p一个n class="token operator">:文件<年代p一个n class="token operator">:扩大<年代p一个n class="token operator">:真正的慢性消耗病<年代p一个n class="token operator">:“.tmp /公共”src<年代p一个n class="token operator">:“* * / *”桌子<年代p一个n class="token operator">:“www”咕哝着说<年代p一个n class="token punctuation">.loadNpmTasks“grunt-contrib-copy”

    将这一行添加到资产/风格/ importer.less

    @ import“. . /供应商/语义用户界面/ semantic.css”

    将JS文件添加到配置/ pipeline.js

    //供应商依赖关系“供应商/ jquery / jquery.min.js”“供应商/语义用户界面/ semantic.js”“供应商/ jsrender / jsrender.js”

    最后,执行此命令将文件从node_modules资产/供应商文件夹中。你只需要为你的项目的每次干净安装做一次:

    繁重副本:开发

    记得加上供应商到你的.gitignore

    测试依赖项安装

    无论选择哪种方法,都需要确保加载了所需的依赖项。为此,将代码替换为视图/ homepage.ejs与以下:

    <h2UI图标头<年代p一个n class="token punctuation">"><设置图标<年代p一个n class="token punctuation">">><div内容<年代p一个n class="token punctuation">">帐户设置<年代p一个n class="token tag"><div子头<年代p一个n class="token punctuation">">管理您的帐户设置和设置电子邮件首选项。<年代p一个n class="token tag">div>div>h2>

    保存文件后,执行a帆抬起.你的主页现在看起来应该是这样的:

    <我mg decoding="async" src="https://uploads.sitepoint.com/wp-content/uploads/2018/01/151665712403-semantic-ui-test.png" alt="semantic-ui-test"loading="lazy">

    在重新启动应用程序后一定要刷新。如果图标缺失或字体看起来不正常,请仔细检查步骤,看看你错过了什么。使用浏览器的控制台查看哪些文件没有加载。否则,继续进行下一阶段。

    创建视图

    当涉及到项目开发时,我喜欢从用户界面开始。我们将使用<一个href="http://www.embeddedjs.com/getting_started.html">嵌入式JavaScript模板创建视图。它是一个模板引擎,默认安装在每个sail .js项目中。但是,您应该意识到它的功能有限,并且已不再处于开发阶段。

    开放配置/ bootstrap.js并插入这一行,以便给我们的网页一个适当的标题。函数之前的现有函数中cb ()声明:

    帆<年代p一个n class="token punctuation">.配置浏览器名称“风帆聊天应用”

    你可以看一下视图/ layout.ejs来看看标题标签设置完成。接下来,我们开始构建主页UI。

    首页设计

    开放/视图/ homepage.ejs并将现有代码替换为:

    <div横幅<年代p一个n class="token punctuation">"><divUI段蓝绿色倒置<年代p一个n class="token punctuation">"><h1UI中心对齐图标头<年代p一个n class="token punctuation">"><聊天图标<年代p一个n class="token punctuation">">><div内容<年代p一个n class="token punctuation">"><一个href/<年代p一个n class="token punctuation">">帆聊天<年代p一个n class="token tag">一个><div子头<年代p一个n class="token punctuation">">与社区讨论您最喜欢的技术!<年代p一个n class="token tag">div>div>h1>div>div><div部分<年代p一个n class="token punctuation">"><divUI三列网格<年代p一个n class="token punctuation">"><div列<年代p一个n class="token punctuation">">div><div列<年代p一个n class="token punctuation">"><divUI中心填充紧凑凸起段<年代p一个n class="token punctuation">"><h3>注册或登录<年代p一个n class="token tag">h3><divui分配器<年代p一个n class="token punctuation">">div>[待办事项:登入表格在此]<年代p一个n class="token tag">div>div><div列<年代p一个n class="token punctuation">">div>div>div>

    要理解上面代码中使用的UI元素,请参考语义UI文档。我在下面列出了具体的链接:

    中创建一个新文件资产/风格/ theme.less并粘贴如下内容:

    .banner一个颜色# fff.centeredmargin-left汽车<年代p一个n class="token important">重要的!margin-right汽车<年代p一个n class="token important">重要的!margin-bottom30.px重要的!.sectionmargin-top30.px.menu这个特性0重要的!.note字体大小11px颜色# 2185 d0#聊天的高度90overflow-y滚动<年代p一个n class="token punctuation">;

    这些都是我们将在项目中使用的自定义样式。其余的样式将来自语义界面图书馆。

    接下来,更新资产/风格/ importer.less要包含我们刚刚创建的主题文件:

    @ import“theme.less”

    执行帆抬起.你的项目现在看起来应该是这样的:

    <我mg decoding="async" src="https://uploads.sitepoint.com/wp-content/uploads/2018/01/151665712804-homepage.png" alt="首页视图"loading="lazy">

    接下来,我们将讨论如何构建导航菜单。

    导航菜单

    这将被创建为一个部分,因为它将由多个视图文件共享。在的观点文件夹,创建一个名为分音.然后创建文件视图/泛音/ menu.ejs并粘贴以下代码:

    <divUI标签图标倒蓝绿色菜单<年代p一个n class="token punctuation">"><一个项<年代p一个n class="token punctuation">"href/聊天<年代p一个n class="token punctuation">"><聊天图标<年代p一个n class="token punctuation">">>聊天室<年代p一个n class="token tag">一个><一个项<年代p一个n class="token punctuation">"href/配置文件<年代p一个n class="token punctuation">"><用户图标<年代p一个n class="token punctuation">">>配置文件<年代p一个n class="token tag">一个><div正确的菜单<年代p一个n class="token punctuation">"><一个项<年代p一个n class="token punctuation">"href/认证/注销<年代p一个n class="token punctuation">"><退出图标<年代p一个n class="token punctuation">">>注销<年代p一个n class="token tag">一个>div>div>

    要理解上面的代码,只需参考<一个href="https://semantic-ui.com/collections/menu.html">菜单文档。

    如果检查上面的代码,您会注意到我们创建了一个链接/聊天/配置文件而且/认证/注销.让我们首先创建视图配置文件而且聊天室

    配置文件

    创建文件视图/ profile.ejs并粘贴以下代码:

    <% include部分/菜单%><年代p一个n class="token tag"><divui容器<年代p一个n class="token punctuation">"><h1以UI为中心的头<年代p一个n class="token punctuation">">配置文件更新!<年代p一个n class="token tag">h1><人力资源><div部分<年代p一个n class="token punctuation">">[TODO把用户表单放在这里]<年代p一个n class="token tag">div>div>

    现在你应该已经熟悉了而且网格UI元素,如果你已经阅读了链接的文档。在文档的根目录,你会注意到我们有一个容器元素。(请在<一个href="https://semantic-ui.com/elements/container.html">容器文档。

    在构建完API之后,我们将在后面构建用户表单。接下来,我们将为聊天室创建一个布局。

    聊天室布局

    聊天室将由三个部分组成:

    • 用户聊天-用户列表
    • 聊天信息-消息列表
    • 聊天后-用于发布新消息的表单。

    创建视图/ chatroom.ejs并粘贴以下代码:

    <% include部分/菜单%><年代p一个n class="token tag"><div聊天”分区<年代p一个n class="token punctuation">"><divUI容器网格<年代p一个n class="token punctuation">"><!——成员列表部分——> .<div四宽柱<年代p一个n class="token punctuation">">[TODO聊天用户]<年代p一个n class="token tag">div><div十二宽柱<年代p一个n class="token punctuation">"><!——聊天消息——>[TODO聊天信息]<年代p一个n class="token tag"><人力资源><!——聊天贴——>[TODO聊天贴]<年代p一个n class="token tag">div>div>div>

    在查看页面之前,我们需要设置路由。

    路由

    开放配置/ routes.js然后像这样更新:

    ' / '视图<年代p一个n class="token operator">:“主页”“/配置文件”视图<年代p一个n class="token operator">:“配置文件”' /聊天'视图<年代p一个n class="token operator">:“聊天室”

    js的路由非常灵活。根据场景,有许多定义路由的方法。这是我们将URL映射到视图的最基本版本。

    启动你的Sails应用,或者如果你的页面还在后台运行,就刷新它。目前主页和其他页面之间没有链接。这是有意为之,因为我们稍后将构建一个基本的身份验证系统,将登录用户重定向到/聊天.现在,使用浏览器的地址栏进行添加/聊天/配置文件在结束URL。

    <我mg decoding="async" src="https://uploads.sitepoint.com/wp-content/uploads/2018/01/151665713005-chat-layout.png" alt="chat-layout"loading="lazy">

    profile-layout"loading=

    在这个阶段,您应该拥有上述视图。让我们继续,开始创建API。

    生成用户API

    我们将使用Sails.js命令行实用程序来生成API。我们需要在这一步停止应用程序:

    生成api用户

    在一秒钟内,我们得到消息“创建了一个新的api!”基本上,一个User.js模型和UserController.js是为我们而生的。让我们更新api /模型/ User.js使用一些模型属性:

    模块<年代p一个n class="token punctuation">.出口属性<年代p一个n class="token operator">:的名字<年代p一个n class="token operator">:类型<年代p一个n class="token operator">:“字符串”要求<年代p一个n class="token operator">:真正的电子邮件<年代p一个n class="token operator">:类型<年代p一个n class="token operator">:“字符串”要求<年代p一个n class="token operator">:真正的独特的<年代p一个n class="token operator">:真正的《阿凡达》<年代p一个n class="token operator">:类型<年代p一个n class="token operator">:“字符串”要求<年代p一个n class="token operator">:真正的defaultsTo<年代p一个n class="token operator">:“https://s.gravatar.com/avatar/e28f6f64608c970c663197d7fe1f5a59?s=60”位置类型<年代p一个n class="token operator">:“字符串”要求<年代p一个n class="token operator">:defaultsTo<年代p一个n class="token operator">:''生物<年代p一个n class="token operator">:类型<年代p一个n class="token operator">:“字符串”要求<年代p一个n class="token operator">:defaultsTo<年代p一个n class="token operator">:''

    我相信上面的代码是不言自明的。默认情况下,Sails.js使用本地磁盘数据库,该数据库基本上是位于.tmp文件夹中。为了测试我们的应用程序,我们需要创建一些用户。最简单的方法是安装<一个href="https://www.npmjs.com/package/sails-seed">sails-seed包

    npm安装sails-seed——保存

    安装后,您会发现该文件配置/ seeds.js都是为你而生的。粘贴以下种子数据:

    模块<年代p一个n class="token punctuation">.出口种子用户<年代p一个n class="token operator">:的名字<年代p一个n class="token operator">:约翰·韦恩的电子邮件<年代p一个n class="token operator">:“johnnie86@gmail.com”《阿凡达》<年代p一个n class="token operator">:“https://randomuser.me/api/portraits/men/83.jpg”位置蒙巴萨的生物<年代p一个n class="token operator">:“大部分时间都待在海滩上”的名字<年代p一个n class="token operator">:“彼得·奎因”电子邮件<年代p一个n class="token operator">:“peter.quinn@live.com”《阿凡达》<年代p一个n class="token operator">:“https://randomuser.me/api/portraits/men/32.jpg”位置“兰利”生物<年代p一个n class="token operator">:“宁可不说”的名字<年代p一个n class="token operator">:“简爱”电子邮件<年代p一个n class="token operator">:“jane@hotmail.com”《阿凡达》<年代p一个n class="token operator">:“https://randomuser.me/api/portraits/women/94.jpg”位置“伦敦”生物<年代p一个n class="token operator">:“喜欢阅读励志书籍”

    现在我们已经生成了一个API,我们应该在文件中配置迁移策略配置/ models.js

    迁移<年代p一个n class="token operator">:“下降”

    在每次启动数据库时,sail .js使用三种迁移策略来确定如何重建数据库:

    • 安全-不要移动,我自己动手
    • 改变—迁移,但尽量保留已有数据
    • 下降-删除所有表并重新构建所有表

    我更喜欢用下降对于开发,因为我倾向于多次迭代。你可以设置改变如果您想保留现有数据。尽管如此,我们的数据库每次都将由种子数据填充。

    现在让我给你看一些很酷的东西。启动您的Sails项目并导航到地址/用户而且/用户/ 1

    <我mg decoding="async" src="https://uploads.sitepoint.com/wp-content/uploads/2018/01/151665713507-users-api.png" alt="users-api"loading="lazy">

    user-api"loading=

    多亏了Sails.js<一个href="https://sailsjs.com/documentation/concepts/blueprints">蓝图API在美国,我们无需编写一行代码就拥有了一个功能齐全的CRUD API。您可以使用Postman访问User API并执行数据操作,例如创建、更新或删除用户。

    现在让我们继续构建概要表单。

    配置文件的形式

    开放视图/ profile.ejs并将现有的TODO行替换为以下代码:

    <imgUI小的居中圆形图像<年代p一个n class="token punctuation">"src< % =数据。阿凡达% ><年代p一个n class="token punctuation">"><divui网格<年代p一个n class="token punctuation">"><形式行动< % =<年代p一个n class="token punctuation">'/ /更新/用户<年代p一个n class="token punctuation">'+数据。id % ><年代p一个n class="token punctuation">"方法帖子<年代p一个n class="token punctuation">"以UI为中心的表单<年代p一个n class="token punctuation">"><div场<年代p一个n class="token punctuation">"><标签>的名字<年代p一个n class="token tag">标签><输入类型文本<年代p一个n class="token punctuation">"的名字的名字<年代p一个n class="token punctuation">"价值<%= data.name %><年代p一个n class="token punctuation">">div><div场<年代p一个n class="token punctuation">"><标签>电子邮件<年代p一个n class="token tag">标签><输入类型文本<年代p一个n class="token punctuation">"的名字电子邮件<年代p一个n class="token punctuation">"价值< % =数据。电子邮件% ><年代p一个n class="token punctuation">">div><div场<年代p一个n class="token punctuation">"><标签>位置<年代p一个n class="token tag">标签><输入类型文本<年代p一个n class="token punctuation">"的名字位置<年代p一个n class="token punctuation">"价值< % =数据。位置% ><年代p一个n class="token punctuation">">div><div场<年代p一个n class="token punctuation">"><标签>生物<年代p一个n class="token tag">标签><文本区域的名字生物<年代p一个n class="token punctuation">"4<年代p一个n class="token punctuation">"关口40<年代p一个n class="token punctuation">">< % =数据。生物% ><年代p一个n class="token tag">文本区域>div> ><年代p一个n class="token tag"><按钮UI右侧浮动橙色按钮<年代p一个n class="token punctuation">"类型提交<年代p一个n class="token punctuation">">更新<年代p一个n class="token tag">按钮>形式>div>

    我们使用<一个href="https://semantic-ui.com/collections/form.html">语义用户界面形式来构建表单界面。如果检查表单的动作值,/ user /更新/ ' + data.id你会发现我用的是蓝图路线。这意味着当用户点击更新按钮,Blueprint的更新操作将被执行。

    但是,为了加载用户数据,我决定在用户控制器中定义一个自定义动作。更新api /控制器/用户控件使用以下代码:

    模块<年代p一个n class="token punctuation">.出口渲染异步请求<年代p一个n class="token punctuation">,响应= >试一试数据<年代p一个n class="token operator">=等待用户findOne电子邮件<年代p一个n class="token operator">:“johnnie86@gmail.com”如果数据<年代p一个n class="token punctuation">)返回响应<年代p一个n class="token punctuation">.notFound“没有找到用户!”响应<年代p一个n class="token punctuation">.视图“配置文件”数据<年代p一个n class="token punctuation">}犯错<年代p一个n class="token punctuation">)响应<年代p一个n class="token punctuation">.serverError犯错<年代p一个n class="token punctuation">)

    在这段代码中,您会注意到我使用了异步/等待语法从数据库中获取User数据。另一种方法是使用回调,对于大多数开发人员来说,回调的可读性不强。我还硬编码了临时加载的默认用户帐户。稍后,当我们设置基本身份验证时,我们将更改它以加载当前登录的用户。

    最后,我们需要改变路线/配置文件开始使用新创建的用户控件.开放配置/路线并按如下方式更新配置文件路由:

    ...“/配置文件”控制器<年代p一个n class="token operator">:“用户”行动<年代p一个n class="token operator">:“呈现”...

    导航到URL/配置文件,你应该有如下的视图:

    <我mg decoding="async" src="https://uploads.sitepoint.com/wp-content/uploads/2018/01/151665714109-profile-view.png" alt="侧面"loading="lazy">

    尝试更改其中一个表单字段并点击更新按钮。你会看到这样的观点:

    <我mg decoding="async" src="https://uploads.sitepoint.com/wp-content/uploads/2018/01/151665714410-profile-update.png" alt="更新个人信息"loading="lazy">

    您将注意到更新已经生效,但是显示的数据是JSON格式的。理想情况下,我们应该有一个视图的个人资料页面视图/ user / findOne.ejs和一个更新个人资料页面/ / user / update.ejs观点.Blueprint系统将猜测用于呈现信息的视图。如果找不到视图,它就会输出JSON。现在,我们将简单地使用这个巧妙的技巧。创建文件/ / user / update.ejs观点并粘贴以下代码:

    <脚本类型text / javascript<年代p一个n class="token punctuation">">窗口位置“/配置文件”脚本>

    下一次执行更新时,将被重定向到/配置文件页面。现在我们有了用户数据,就可以创建文件了视图/泛音/ chat-users.js用于视图/ chatroom.ejs.创建文件后,粘贴以下代码:

    <divUI基本段<年代p一个n class="token punctuation">"><h3>成员h3><人力资源><dividusers-content<年代p一个n class="token punctuation">"UI中间对齐选择列表<年代p一个n class="token punctuation">">div>div>// jsrender模板<脚本idusersTemplate<年代p一个n class="token punctuation">"类型文本/ x-jsrender<年代p一个n class="token punctuation">">< div class = "项目" > < img类=“ui的化身形象”src = "{{:阿凡达}}" > < div class = "内容" > < div class = "头" >{{:名称}}< / div > < / div > < / div >脚本><脚本类型text / javascript<年代p一个n class="token punctuation">">function loadUsers(){//加载现有用户io.socket。get('/user', function(用户,响应){renderChatUsers(用户);});//监听新的和更新的用户io.socket。On ('user', function(body) {io.socket。get('/user', function(用户,响应){renderChatUsers(用户);});});}函数renderChatUsers(data) {const template = $.templates('#usersTemplate');let htmlOutput = template.render(data);$ (' # users-content ') . html (htmlOutput); }脚本>

    对于这个视图,我们需要一种客户端呈现方法来实时更新页面。这里,我们用到了<一个href="https://github.com/BorisMoore/jsrender">jsrender库,比EJS更强大的模板引擎。的美jsrender它可以接受数组或单个对象文字,并且模板仍然会正确呈现。如果我们做这个ejs,我们需要结合如果语句和循环来处理这两种情况。

    让我来解释一下客户端JavaScript代码的流程:

    1. loadUsers ().当页面第一次加载时,我们使用sail .js套接字库来执行得到请求用户。此请求将由Blueprint API处理。然后我们将接收到的数据传递给renderChatUsers(数据)函数。
    2. 仍然在loadUsers ()函数,我们使用io.socket.on函数。我们监听与模型相关的事件用户.当我们收到通知时,我们再次获取用户并替换现有的HTML输出。
    3. renderChatUsers(数据).这里我们获取一个带有id的脚本usersTemplate使用jQuery模板()函数。注意它的类型是文本/ x-jsrender.通过指定自定义类型,浏览器将忽略并跳过该部分,因为它不知道它是什么。然后我们使用template.render ()函数将模板与数据合并。这个过程将生成一个HTML输出,然后我们将其插入到HTML文档中。

    我们写入的模板profile.ejs在Node服务器上呈现,然后以HTML的形式发送到浏览器。对于聊天用户,我们需要执行客户端渲染。这将允许聊天用户在不刷新浏览器的情况下看到新用户加入群组。

    在测试代码之前,我们需要进行更新视图/ chatroom.ejs以包括新创建的聊天用户部分。取代[TODO聊天用户]下面的代码:

    …html <%包含部分/聊天用户。Ejs %>…

    在同一个文件中,在最后添加这个脚本:

    <脚本类型text / javascript<年代p一个n class="token punctuation">">窗口onload函数loadUsers脚本>

    该脚本将调用loadUsers ()函数。为了确认这是有效的,让我们执行一个帆抬起并导航到/聊天URL。

    <我mg decoding="async" src="https://uploads.sitepoint.com/wp-content/uploads/2018/01/151665714611-chat-users.png" alt="聊天用户"loading="lazy">

    你的视图应该像上图那样。如果有,让我们继续构建聊天室API。

    ChatMessage API

    和之前一样,我们将使用Sails.js生成API:

    风帆生成api ChatMessage

    接下来,填充api /模型/ ChatMessage.js具有这些属性:

    模块<年代p一个n class="token punctuation">.出口属性<年代p一个n class="token operator">:消息<年代p一个n class="token operator">:类型<年代p一个n class="token operator">:“字符串”要求<年代p一个n class="token operator">:真正的createdBy<年代p一个n class="token operator">:模型<年代p一个n class="token operator">:“用户”要求<年代p一个n class="token operator">:真正的

    注意,我们已经声明了与用户通过createdBy属性。接下来,我们需要用一些聊天消息填充磁盘数据库。我们用配置/ bootstrap.js.按如下方式更新整个代码。我们使用异步/等待语法来简化我们的代码,避免回调地狱:

    模块<年代p一个n class="token punctuation">.出口引导异步函数cb帆<年代p一个n class="token punctuation">.配置浏览器名称“风帆聊天应用”//生成聊天消息试一试messageCount<年代p一个n class="token operator">=ChatMessage如果messageCount<年代p一个n class="token operator">>0返回//不重复消息用户<年代p一个n class="token operator">=等待用户找到如果用户<年代p一个n class="token punctuation">.长度> =3.控制台日志“生成消息……”msg1<年代p一个n class="token operator">=等待ChatMessage创建消息<年代p一个n class="token operator">:“嘿!欢迎来到这个社区!”createdBy<年代p一个n class="token operator">:用户<年代p一个n class="token punctuation">[1控制台日志"已创建聊天消息:"+msg1<年代p一个n class="token punctuation">.idmsg2<年代p一个n class="token operator">=等待ChatMessage创建消息<年代p一个n class="token operator">:“最近怎么样?”createdBy<年代p一个n class="token operator">:用户<年代p一个n class="token punctuation">[2控制台日志"已创建聊天消息:"+msg2<年代p一个n class="token punctuation">.idmsg3<年代p一个n class="token operator">=等待ChatMessage创建消息<年代p一个n class="token operator">:“超级兴奋!”createdBy<年代p一个n class="token operator">:用户<年代p一个n class="token punctuation">[0控制台日志"已创建聊天消息:"+msg3<年代p一个n class="token punctuation">.id其他的控制台日志“跳过消息生成”犯错<年代p一个n class="token punctuation">)控制台错误犯错<年代p一个n class="token punctuation">)//当你完成Bootstrap时触发这个回调方法是非常重要的!(否则你的服务器将永远不会提升,因为它正在等待Bootstrap)cb

    最棒的是种子生成器之前运行过bootstrap.js.这样我们就确定了用户首先创建了数据,以便我们可以使用它来填充createdBy字段。拥有测试数据将使我们能够在构建用户界面时快速迭代。

    聊天消息界面

    继续创建一个新文件视图/泛音/ chat-messages.ejs,然后放置以下代码:

    这里的逻辑与聊天用户.在听力部分有一个关键的区别。我们使用append而不是替换呈现的输出。然后我们做一个滚动动画到列表的底部,以确保用户看到新的传入消息。

    接下来,让我们更新一下chatroom.ejs包括新的聊天信息部分也要更新脚本调用loadMessages ()功能:

    ...<年代p一个n class="token comment"><!——聊天消息——><%包含部分/聊天消息。Ejs %>…<年代p一个n class="token tag"><脚本类型text / javascript<年代p一个n class="token punctuation">">...loadMessages...脚本>

    你的视图现在应该是这样的:

    <我mg decoding="async" src="https://uploads.sitepoint.com/wp-content/uploads/2018/01/151665714912-chat-messages.png" alt="聊天信息"loading="lazy">

    现在让我们构建一个允许用户向聊天室发布消息的简单表单。

    聊天帖子界面

    创建一个新文件视图/部分/ chat-post.ejs然后粘贴这段代码:

    <divUI基本段<年代p一个n class="token punctuation">"><divui表单<年代p一个n class="token punctuation">"><divui字段<年代p一个n class="token punctuation">"><标签>发布消息<年代p一个n class="token tag">标签><文本区域id编辑框<年代p一个n class="token punctuation">"2<年代p一个n class="token punctuation">">文本区域>div><按钮idpost-btn<年代p一个n class="token punctuation">"UI右侧浮动大橙色按钮<年代p一个n class="token punctuation">"类型提交<年代p一个n class="token punctuation">">帖子<年代p一个n class="token tag">按钮>div><dividpost-err<年代p一个n class="token punctuation">"UI微小紧凑的负面消息<年代p一个n class="token punctuation">"风格显示没有一个<年代p一个n class="token punctuation">;><p>哦!出了问题。<年代p一个n class="token tag">p>div>div>

    这里我们用的是using语义用户界面元素来构建表单。接下来将这个脚本添加到文件底部:

    <脚本类型text / javascript<年代p一个n class="token punctuation">">function activateChat() {const postField = $('#post-field');const postButton = $('#post-btn');const postErr = $('#post-err');//绑定点击事件postButton.click(postMessage);//绑定输入按键事件postField.keypress(function(e) {var keycode = (e. keycode ?e.keyCode: e.which);if (keycode == '13') {postMessage();}});function postMessage() {if(postField.val() == "") {alert("请输入消息!");} else {let text = postField.val(); io.socket.post('/postMessage', { message: text }, function(resData, jwRes) { if(jwRes.statusCode != 200) { postErr.html("

    " + resData.message +"

    ") postErr.show(); } else { postField.val(''); // clear input field } }); } } }脚本>

    这个脚本由两个函数组成:

    • activateChat ().该函数将发布按钮绑定到单击事件,将消息框(发布字段)绑定到按下(enter)事件。当任何一方被解雇时postMessage ()函数被调用。
    • postMessage.这个函数首先进行快速验证,以确保后输入字段不是空白。如果在输入字段中提供了消息,则使用io.socket.post ()函数将消息发送回服务器。这里我们使用一个经典的回调函数来处理来自服务器的响应。如果发生错误,则显示错误消息。如果我们得到一个200状态码,这意味着消息已被捕获,我们将清除post输入字段,准备输入下一条消息。

    如果你回到聊天信息脚本中,您将看到我们已经放置了用于检测和呈现传入消息的代码。你还应该注意到io.socket.post ()正在向URL发送数据/ postMessage.这不是蓝图路线,而是自定义路线。因此,我们需要为它编写代码。

    前往api /控制器/ UserController.js然后插入这段代码:

    模块<年代p一个n class="token punctuation">.出口postMessage异步请求<年代p一个n class="token punctuation">,响应= >//确保这是一个套接字请求(不是传统的HTTP)如果请求<年代p一个n class="token punctuation">.isSocket返回响应<年代p一个n class="token punctuation">.badRequest试一试用户<年代p一个n class="token operator">=等待用户findOne电子邮件<年代p一个n class="token operator">:“johnnie86@gmail.com”味精<年代p一个n class="token operator">=等待ChatMessage创建消息<年代p一个n class="token operator">:请求<年代p一个n class="token punctuation">.身体消息createdBy<年代p一个n class="token operator">:用户<年代p一个n class="token punctuation">}如果味精<年代p一个n class="token punctuation">.id错误“消息处理失败!”味精<年代p一个n class="token punctuation">.createdBy用户<年代p一个n class="token punctuation">;ChatMessagepublishCreate味精<年代p一个n class="token punctuation">)犯错<年代p一个n class="token punctuation">)返回响应<年代p一个n class="token punctuation">.serverError犯错<年代p一个n class="token punctuation">)返回响应<年代p一个n class="token punctuation">.好吧

    因为我们还没有设置基本的身份验证,所以我们对用户进行了硬编码johnnie86@gmail.com目前作为这条信息的作者。我们使用Model.create ()水线ORM函数创建一个新的记录。这是一种奇特的插入记录的方式,无需编写SQL代码。接下来,我们向所有套接字发送一个通知事件,通知他们已经创建了一个新消息。我们用ChatMessage.publishCreate ()函数,它在蓝图API中定义。在我们发出消息之前,我们要确保createdBy字段中填充用户对象。这是由聊天信息部分以访问虚拟形象和创建消息的用户的名称。

    接下来,转到配置/ routes.js绘制/ postMessage的URLpostMessage我们刚刚定义的动作。插入以下代码:

    ...' /聊天'视图<年代p一个n class="token operator">:“聊天室”//在这里加逗号' / postMessage '控制器<年代p一个n class="token operator">:“ChatMessageController”行动<年代p一个n class="token operator">:“postMessage”...

    开放视图/ chatroom.js并包括chat-post部分。我们也会调用activateChat ()函数在loadMessages ()功能:

    ...<%包含部分/聊天消息。Ejs %>…<年代p一个n class="token tag"><脚本类型text / javascript<年代p一个n class="token punctuation">">...activateChat...脚本>

    刷新页面并尝试发送几条消息。

    <我mg decoding="async" src="https://uploads.sitepoint.com/wp-content/uploads/2018/01/151665715213-chat-post.png" alt="chat-post"loading="lazy">

    现在您应该有了一个功能正常的聊天系统。检查项目源代码,以防遇到困难。

    基本身份验证

    设置适当的身份验证和授权系统超出了本教程的范围。所以我们将满足于一个基本的无密码认证系统。让我们首先构建注册和登录表单。

    登录/注册表格

    创建一个新文件视图/ auth-form.ejs并粘贴如下内容:

    <形式方法帖子<年代p一个n class="token punctuation">"行动/身份验证/认证<年代p一个n class="token punctuation">"ui表单<年代p一个n class="token punctuation">"><div场<年代p一个n class="token punctuation">"><标签>全名<年代p一个n class="token tag">标签><输入类型文本<年代p一个n class="token punctuation">"的名字的名字<年代p一个n class="token punctuation">"占位符全名<年代p一个n class="token punctuation">"价值<%= typeof name !=<年代p一个n class="token punctuation">'未定义的<年代p一个n class="token punctuation">'?名称:<年代p一个n class="token punctuation">'% ><年代p一个n class="token punctuation">">div><div必需字段<年代p一个n class="token punctuation">"><标签>电子邮件<年代p一个n class="token tag">标签><输入类型电子邮件<年代p一个n class="token punctuation">"的名字电子邮件<年代p一个n class="token punctuation">"占位符电子邮件<年代p一个n class="token punctuation">"价值<%= typeof email !=<年代p一个n class="token punctuation">'未定义的<年代p一个n class="token punctuation">'?电子邮件:<年代p一个n class="token punctuation">'% ><年代p一个n class="token punctuation">">div><按钮UI蓝绿色按钮<年代p一个n class="token punctuation">"类型提交<年代p一个n class="token punctuation">"的名字行动<年代p一个n class="token punctuation">"价值注册<年代p一个n class="token punctuation">">报名<年代p一个n class="token entity named-entity" title="&">,登录<年代p一个n class="token tag">按钮><按钮UI蓝色按钮<年代p一个n class="token punctuation">"类型提交<年代p一个n class="token punctuation">"的名字行动<年代p一个n class="token punctuation">"价值登录<年代p一个n class="token punctuation">">登录<年代p一个n class="token tag">按钮><p请注意<年代p一个n class="token punctuation">">*只提供登入电邮<年代p一个n class="token tag">p>形式><% if(typeof error != 'undefined') {%> . if(typeof error != 'undefined'<年代p一个n class="token tag"><divUI错误消息<年代p一个n class="token punctuation">"><div头<年代p一个n class="token punctuation">">< % =错误。标题% ><年代p一个n class="token tag">div><p>< % =错误。消息% ><年代p一个n class="token tag">p>div><%} %>

    的下一个开放视图/ homepage.ejs用include语句替换TODO行:

    ...<% include partial /auth-form。Ejs %>…

    我们已经创建了一个表单,允许您通过提供姓名和电子邮件的输入来创建一个新帐户。当你点击注册和登录,就会创建一个新的用户记录,然后您就可以登录了。但是,如果该电子邮件已被其他用户使用,则会显示错误消息。如果您只是想登录,只需提供电子邮件地址并单击登录按钮。身份验证成功后,您将被重定向到/聊天URL。

    现在,我刚才说的一切都不管用。我们需要实现这个逻辑。首先,让我们导航到/地址确认auth-form看起来商品。

    <我mg decoding="async" src="https://uploads.sitepoint.com/wp-content/uploads/2018/01/151665715414-auth-form.png" alt="auth-form"loading="lazy">

    政策

    现在我们建立了一个认证系统,我们需要保护/聊天而且/配置文件来自公众访问的路由。应该只允许经过身份验证的用户访问它们。开放配置/ policies.js然后插入这段代码:

    ChatMessageController‘*’“sessionAuth”用户控件‘*’“sessionAuth”

    通过指定控制器的名称,我们还有效地阻止了Blueprint API为用户和聊天消息提供的所有路由。不幸的是,策略只适用于控制器。这意味着路线/聊天无法在当前状态下进行保护。我们需要为它定义一个自定义操作。开放api /控制器/ ChatroomController.js然后插入这段代码:

    ...渲染请求<年代p一个n class="token punctuation">,响应= >返回响应<年代p一个n class="token punctuation">.视图“聊天室”

    的路由配置/聊天有了这个配置/ routes.js

    ...' /聊天'控制器<年代p一个n class="token operator">:“ChatMessageController”行动<年代p一个n class="token operator">:“呈现”...

    /聊天路由现在应该被保护,不被公众访问。如果你重启你的应用并尝试访问/配置文件/聊天/用户/ chatmessage,你会看到以下禁止的信息:

    <我mg decoding="async" src="https://uploads.sitepoint.com/wp-content/uploads/2018/01/151665715915-forbidden.png" alt="被禁止的"loading="lazy">

    如果您想将用户重定向到登录表单,请转到api /政策/ sessionAuth然后像这样用重定向调用替换禁止调用:

    ...//返回res.forbidden('您不允许执行此操作。');返回res<年代p一个n class="token punctuation">.重定向' / '...

    尝试再次访问禁止页面,您将自动重定向到主页。现在让我们实现注册和登录代码。

    认证控制器和服务

    为了运行这个命令,你需要先停止Sails.js:

    风帆生成控制器认证

    这将创建一个空白api /控制器/ AuthController对我们来说。打开它并插入以下代码:

    进行身份验证异步请求<年代p一个n class="token punctuation">,响应= >//注册用户如果请求<年代p一个n class="token punctuation">.身体行动= =“注册”//验证注册表单//检查邮件是否已注册//创建新用户//登录用户注销请求<年代p一个n class="token punctuation">,响应= >//注销用户

    我已经在评论中解释了逻辑将如何流动。我们可以把相关代码放在这里。然而,Sails.js建议我们保持我们的控制器代码简单,易于遵循。为了实现这一点,我们需要编写helper函数来帮助我们处理上面的每个注释任务。为了创建这些帮助函数,我们需要创建一个服务。通过创建一个新文件来做到这一点吗api /服务/ AuthService.js.插入以下代码:

    /** * AuthService.js ** */常量功能<年代p一个n class="token operator">=需要“功能”//在哪里显示认证错误常量视图<年代p一个n class="token operator">=“主页”模块<年代p一个n class="token punctuation">.出口sendAuthError响应<年代p一个n class="token punctuation">,标题<年代p一个n class="token punctuation">,消息<年代p一个n class="token punctuation">,选项= >选项<年代p一个n class="token operator">=选项<年代p一个n class="token operator">||常量电子邮件<年代p一个n class="token punctuation">,的名字<年代p一个n class="token punctuation">}选项<年代p一个n class="token punctuation">;响应<年代p一个n class="token punctuation">.视图视图<年代p一个n class="token punctuation">,错误<年代p一个n class="token operator">:标题<年代p一个n class="token punctuation">,消息<年代p一个n class="token punctuation">}电子邮件<年代p一个n class="token punctuation">,的名字<年代p一个n class="token punctuation">}返回validateSignupForm请求<年代p一个n class="token punctuation">,响应= >如果请求<年代p一个n class="token punctuation">.身体的名字= =''返回AuthServicesendAuthError响应<年代p一个n class="token punctuation">,“注册失败!”“你必须提供一个名字来注册”电子邮件<年代p一个n class="token operator">:请求<年代p一个n class="token punctuation">.身体电子邮件其他的如果请求<年代p一个n class="token punctuation">.身体电子邮件= =''返回AuthServicesendAuthError响应<年代p一个n class="token punctuation">,“注册失败!”“您必须提供电子邮件地址才能注册”的名字<年代p一个n class="token operator">:请求<年代p一个n class="token punctuation">.身体的名字返回真正的checkDuplicateRegistration异步请求<年代p一个n class="token punctuation">,响应= >试一试existingUser<年代p一个n class="token operator">=等待用户findOne电子邮件<年代p一个n class="token operator">:请求<年代p一个n class="token punctuation">.身体电子邮件如果existingUser<年代p一个n class="token punctuation">)常量选项<年代p一个n class="token operator">=电子邮件<年代p一个n class="token operator">:请求<年代p一个n class="token punctuation">.身体电子邮件的名字<年代p一个n class="token operator">:请求<年代p一个n class="token punctuation">.身体的名字返回AuthServicesendAuthError响应<年代p一个n class="token punctuation">,“重复注册!”“所提供的电子邮件已注册”选项<年代p一个n class="token punctuation">)返回真正的犯错<年代p一个n class="token punctuation">)响应<年代p一个n class="token punctuation">.serverError犯错<年代p一个n class="token punctuation">)返回registerUser异步数据<年代p一个n class="token punctuation">,响应= >试一试常量的名字<年代p一个n class="token punctuation">,电子邮件<年代p一个n class="token punctuation">}数据<年代p一个n class="token punctuation">;常量《阿凡达》<年代p一个n class="token operator">=功能<年代p一个n class="token punctuation">.url电子邮件<年代p一个n class="token punctuation">,年代<年代p一个n class="token operator">:200“https”分类列出<年代p一个n class="token operator">=等待用户创建的名字<年代p一个n class="token punctuation">,电子邮件<年代p一个n class="token punctuation">,《阿凡达》<年代p一个n class="token punctuation">}//让所有socket知道一个新用户已经创建用户publishCreate分类列出<年代p一个n class="token punctuation">)返回分类列出<年代p一个n class="token punctuation">;犯错<年代p一个n class="token punctuation">)响应<年代p一个n class="token punctuation">.serverError犯错<年代p一个n class="token punctuation">)返回登录异步请求<年代p一个n class="token punctuation">,响应= >试一试用户<年代p一个n class="token operator">=等待用户findOne电子邮件<年代p一个n class="token operator">:请求<年代p一个n class="token punctuation">.身体电子邮件如果用户<年代p一个n class="token punctuation">)//登录通过请求<年代p一个n class="token punctuation">.会话用户标识用户<年代p一个n class="token punctuation">.id请求<年代p一个n class="token punctuation">.会话通过身份验证真正的返回响应<年代p一个n class="token punctuation">.重定向' /聊天'其他的//登录失败返回AuthServicesendAuthError响应<年代p一个n class="token punctuation">,“登录失败!”“所提供的电子邮件未注册”电子邮件<年代p一个n class="token operator">:请求<年代p一个n class="token punctuation">.身体电子邮件犯错<年代p一个n class="token punctuation">)返回响应<年代p一个n class="token punctuation">.serverError犯错<年代p一个n class="token punctuation">)注销请求<年代p一个n class="token punctuation">,响应= >请求<年代p一个n class="token punctuation">.会话用户标识请求<年代p一个n class="token punctuation">.会话通过身份验证响应<年代p一个n class="token punctuation">.重定向' / '

    仔细检查代码。作为中级开发人员,您应该能够理解其中的逻辑。这里我没有做任何花哨的东西。然而,我想提几件事:

    • 功能。你需要安装Gravatar。它是一个JavaScript库,用于生成基于电子邮件地址的Gravatar url。
      bash NPM install gravatar——保存
    • User.publishCreate(列出).就像ChatMessages,我们触发一个事件,通知所有套接字一个新用户已经创建。这将导致所有已登录的客户端重新获取用户数据。审查视图/部分/ chat-users.js看看我在说什么
    • request.session.js提供了一个<一个href="https://sailsjs.com/documentation/concepts/sessions">会话存储我们可以用它来在页面请求之间传递数据。默认的Sails.js会话存在于内存中,这意味着如果您停止服务器,会话数据就会丢失。在AuthService,我们使用session来存储用户标识而且通过身份验证的地位。

    在逻辑上AuthService.js完全就位后,我们可以继续进行更新api /控制器/ AuthController使用以下代码:

    模块<年代p一个n class="token punctuation">.出口进行身份验证异步请求<年代p一个n class="token punctuation">,响应= >常量电子邮件<年代p一个n class="token operator">=请求<年代p一个n class="token punctuation">.身体电子邮件如果请求<年代p一个n class="token punctuation">.身体行动= =“注册”常量的名字<年代p一个n class="token operator">=请求<年代p一个n class="token punctuation">.身体的名字//验证注册表单如果AuthServicevalidateSignupForm请求<年代p一个n class="token punctuation">,响应<年代p一个n class="token punctuation">)返回//检查邮件是否已注册常量duplicateFound<年代p一个n class="token operator">=等待AuthServicecheckDuplicateRegistration请求<年代p一个n class="token punctuation">,响应<年代p一个n class="token punctuation">)如果duplicateFound<年代p一个n class="token punctuation">)返回//创建新用户常量分类列出<年代p一个n class="token operator">=等待AuthServiceregisterUser的名字<年代p一个n class="token punctuation">,电子邮件<年代p一个n class="token punctuation">}响应<年代p一个n class="token punctuation">)如果分类列出<年代p一个n class="token punctuation">)返回//尝试登录常量成功<年代p一个n class="token operator">=等待AuthService登录请求<年代p一个n class="token punctuation">,响应<年代p一个n class="token punctuation">)注销请求<年代p一个n class="token punctuation">,响应= >AuthService注销请求<年代p一个n class="token punctuation">,响应<年代p一个n class="token punctuation">)

    看看我们的控制器有多简单易读。接下来,让我们做一些最后的修饰。

    最后

    方法中的硬编码值现在已经设置了身份验证,我们应该删除postMessage行动api /控制器/ ChatMessageController.将邮件代码替换为以下代码:

    ...用户<年代p一个n class="token operator">=等待用户findOneid<年代p一个n class="token operator">:请求<年代p一个n class="token punctuation">.会话用户标识...

    我想提到一些您可能没有注意到的东西,如果您查看的注销URL视图/泛音/ menu.ejs我们把这个地址放在这里/认证/注销.如果你看配置/ routes.js,你会注意到我们没有为它放置URL。令人惊讶的是,当我们运行代码时,它可以工作。这是因为Sails.js使用约定来确定需要哪个控制器和动作来解析特定地址。

    到目前为止,您应该已经拥有了一个功能性的MVP聊天应用程序。启动你的应用并测试以下场景:

    • 注册时无需输入任何内容
    • 只填写姓名报名
    • 只通过填写电子邮件注册
    • 通过填写姓名和注册的电子邮件注册-例如,johnnie86@gmail.comjane@hotmail.com
    • 用你的名字和邮箱注册
    • 更新个人资料
    • 试着发布一条空白消息
    • 发布一些信息
    • 打开另一个浏览器,以另一个用户登录,把每个浏览器并排放在一起聊天
    • 注销并创建一个新帐户。

    duplicate-registration"loading=

    multiple-chats-test"loading=

    唷!这是我们一次性实现并测试的许多功能。再过几个星期,我们就可以推出一个集成了更多功能的聊天系统,比如多个聊天室、频道附件、笑脸图标和社交账户集成!

    总结

    在本教程中,我们没有将登录用户的名称放在顶部菜单的某个位置。你应该有能力自己解决这个问题。如果您已经阅读了整个教程,那么您现在应该能够熟练地使用Sails.js构建应用程序。

    本教程的目标是向您展示如何使用非javascript MVC框架,用相对较少的代码行构建令人惊叹的东西。使用Blueprint API将帮助您更快地实现特性。我还建议你学会集成一个更强大的前端库——比如React、Angular或Vue——来创建一个更具交互性的web应用程序。此外,学习如何为Sails.js编写测试以自动化测试过程是编程武器库中的一个重要武器。

    <一个年代ide class="flex space-x-4">

    分享本文

    <按钮一个ria-label="Share Sitepoint on facebook" data-network="facebook" class="social-share-button mr-2 cursor-pointer transform transition duration-200 hover:scale-125 text-primary-700">
    <divUI基本段<年代p一个n class="token punctuation">"风格高度70vh><h3>社区的对话h3><人力资源><divid聊天的<年代p一个n class="token punctuation">"ui饲料<年代p一个n class="token punctuation">">div>div><脚本idchatTemplate<年代p一个n class="token punctuation">"类型文本/ x-jsrender<年代p一个n class="token punctuation">"> 脚本><脚本类型text / javascript<年代p一个n class="token punctuation">">function loadMessages(){//加载现有聊天消息io.socket。get('/chatMessage',函数(消息,响应){renderChatMessages(消息);});//监听新的聊天消息io.socket。on('chatmessage',函数(body) {renderChatMessages(body.data);});}函数renderChatMessages(data) {const chatContent = $('#chat-content');const template = $.templates('# chattrplate ');let htmlOutput = template.render(data);chatContent.append (htmlOutput); // automatically scroll downwards const scrollHeight = chatContent.prop("scrollHeight"); chatContent.animate({ scrollTop: scrollHeight }, "slow"); }脚本>
    {{:createdBy.name}} posted on
    {{:createdAt}}
    {{:message}}
    Baidu