node=day6

(1)反馈

  

   

 

   

 

 

(2)项目结构

  1、新建项目文件目录forum(社区)

  2、初始化项目,新建项目说明文件package.json

    

  3、初始化git仓库,用于后期向git推送发布

    

  4、新建项目说明文档README.md,后期在Git上也可以浏览

    

 

   5、创建git上传忽略文件类型设置文件“.gitignore”

    

 

   6、安装核心包Express(开启创建服务)、mongoose(数据库)

    

     下载完毕后会发现,npm新版在安装第三方依赖时,会自动创建package-lock.json锁文件,将记录依赖树,锁定版本

   7、创建静态资源开放目录public,给客户端用

    

   8、创建入口文件,编写代码

注意:这里需要开放静态资源public,同时因为后期要用jquery和bootstrap,所以这里开放node_modules目录,让前端直接访问该目录下的资源

    

     查看Express官方文档会发现开放静态资源有个写法

    

     这里可以对上述代码做下修改

    

     这里注意:path为核心模块(路径操作模块),所以需要引入,接下来便可以通过url浏览静态资源。如下所示

    

     

上面path.join(__dirname,'./public')与之前相比,是将路径变为绝对路径。这里 便涉及到两个知识点:path路径操作模块和__dirname文件路径。接下来做下介绍

 

 

(3)path路径操作模块

  详情参见path路径操作模块.

 

(4)dirname和filename

  详情参见node中其他成员(非模块成员)之dirname和filename.

  

 

 

 

(5)art-template模板引擎中的include-extend-block

  1、接下来开始渲染页面,此时需要配合模板引擎

因为这里用的Express搭建的服务,所以需要用到模板引擎express-art-template,同时还需要art-template。因为express-art-template是基于art-template开发的
新版npm5.xxx之后不需要加--save参数,即可默认加上

      

  2、接下来启动服务,配置模板引擎相关参数

    

注意:这里避免相对路径,使用动态绝对路径

    

    index.html内容:

    

     启动后,测试如下

    

 

    因为放在了public开放目录下,所以也可以通过开放资源url访问

    

 

 

     接下来加个模板参数进行渲染

 

  3、模板参数渲染

    

    

    结果如下所示

    

 

 

     

对比分析可得静态资源经过了模板编译,此时渲染成了我们想要的内容 

  4、公共部分抽离

分析可得在开发中,有的地方例如网页头部导航和底部,在很多页面用到,此时便可以抽取出来

    接下来打开art-template官网文档,查看相关配置(这里选择简体中文,方便阅读)

 

    

 

     然后查找语法

    

 

     接下来看下子模板和模板继承

    ①首先新建文件header.html

    

 

     

 

     ②接下来在其他页面(同级index.html)引入

    

    

     ③同理,建立公共底部模板文件footer.html

     

     

     

     渲染结果如下

    

 

       ④进一步封装,目前为止已经把头部、底部抽离出去,但还有很多架构一样

    

此时便可以利用模板继承

 

    ⑤模板继承

接下来新建布局模板layout.html,将原来的index.html文件内容粘贴过去做下修改

    

 

     接下来在index.html页面去继承

    

 

     此时页面渲染结果如下

    

分析:因为index.html没有填入内容,所以这里展示默认内容

    ⑥接下来开始填坑

    

分析可知:填坑内容与留坑语法类似,此时结果如下

    

 

     ⑦公共模板完善

    因为接下来要用到bootstrap和jquery,所以直接在公共模板页面引入,首先下载第三方依赖包

    

    补充(dist发布目录):

    

 

     

 

     查看效果,发现文件引入成功,字体样式已经改动

    

此时模板页和后代子页面都已经整合到一起

  5、art-template多环境应用

模板引擎art-template可以在node服务器环境应用,也可以在浏览器环境应用,原因在于源码里没有涉及具体环境API(模板引擎只操作字符串,与DOM操作、文件操作均无关

  6、其他相关模板引擎

   

  7、公共模板页的设计

关于公共模板页layout.html的设计主要注意:
    1、将公共部分放到这里
    2、在需要后代继承覆盖的地方留坑,并加上“默认内容”

    为了后代各个页面拥有自己的样式和脚本,所以还需要在样式和脚本处留坑,但这里注意:默认位置,后期会被覆盖,也可以不填,之后再做修改

    

 

     接下来在index.html对应填坑即可

    

 

     

 

     对于脚本部分,为了防止混淆,我们可以命名为script  

    

 

     这里对于留坑位置做下修改,都给去掉

    

 

     然后在index页面做下样式定制

    

 

     此时网页记载完毕后的内容如下

    

 

 

  

(6)案例资源页面

  这里便涉及到文件分类和命名,之所以用_,是因为要和其他业务主页面区分开来

  

 

   对于公共页面局部,可以抽离归类到相关文件夹,例如_layouts(布局)目录,存放如下(因为可能有多个公共模板,所以命名为layouts)

  

  _partials(部分)目录,存放如下,存放公共头部、尾部、导航等

  

 

   所以接下来依次编写静态页面,即静态资源页面设计和命名,详见node(day6)之静态资源页面设计和命名.

 

(7)设计注册、登录、退出路由

  

 

   相对之前来说多了几个目录controllers、models、routes等。

  

 

   接下来设计下路由

  

 

注意:有些功能是需要权限的,例如发布一篇博客,如果不登录是无法发表的

  

 

(8)配置注册登录路由

  1、路由提取

正如之前所讲,入口文件不做路由处理

  

一般小型项目,可以直接在根目录下新建router.js处理路由。
但当项目较大,请求越来越多时,最好将其在routes目录下分类管理。
    例如:注册登录退出相关的操作,放到routes下的session.js(会话),因为注册登录退出操作,都相当于在和服务器进行会话
     新建话题、删除话题、修改话题、查看话题列表等操作,放到routes下的topic.js

  例如:这里在routes/router.js设计渲染首页路由,如下所示(      备注:后期修改为routes下各个子文件操作,然后通过routes/router.js统一管理              )

  

 

   接下来在入口文件require引入加载并use使用

   

  2、接下来添加其他路由操作

  

 

   之后进行验证,点击登录、注册按钮跳转到相应页面即可

  

 

(9)快速启动配置

为了快速启动项目,接下来在项目说明文件配置scripts项,如下所示

    

  配置完毕后,以后再启动项目只需输入指令“npm start”

  

 

 

 

(10)处理注册页面,配置Express中间件body-parser

  接下来看下注册页模板内容

  

 

   点击提交时利用jQuery操作表单提交,所以这里需要引入jquery

  

serialize() 方法通过序列化表单值创建 URL 编码文本字符串,
序列化的值可在生成 AJAX 请求时用于 URL 查询字符串中
关于jQuery的ajax里dataType预期服务器返回数据类型,详见jQuery的ajax里dataType预期服务器返回数据类型.

  这里的data为序列化后的表单数据,打印如下

  

 

   接下来获取表单post提交数据,这时便需要配置body-parser中间件

  

 

   1、下载body-parser中间件

    

  2、在入口文件进行相关配置,注意:一定要放在挂载路由之前配置

    

    此时在路由配置文件输出打印post提交数据

    

 

     测试如下:

    

 

     

 

     如果body-parser配置放到了挂载路由到app实例之前,则获取不到post提交数据

    

 

     接下来便要开始操作数据库,这里我们使用mongoose第三方包实现,首先要设计数据模型

 

 

(11)设计数据库(用户数据模型)

   1、分析

因为除了用户数据,还有话题相关数据、评论相关数据等,所以这里需要设计多个数据模型,将其放到models目录下

    

 

     models下有多个数据模型,代表多个集合。user.js代表用户数据集合

  2、设计user.js用户数据集合

注意:集合命名为大写单数User,最终数据库集合名会变为小写复数users

    

  3、设计文档格式

    首先是基本信息

    

 

     另外,除了基本信息,还有些看不到的信息,例如创建时间、修改时间... ...,这里加入创建即注册时间

    

 

     重点分析:

    

这里可能会有疑问:为什么Date.now没有加函数执行符?
  原因:加入函数执行符会即时调用

    

这里传入方法Date.now,当你去new Model时即实例化模型,如果没有传递create_time,则mongoose就会调用default指定的Date.now方法使用其返回值作为默认值
对比分析:例如type为a+b,则在new Schema时便自动计算出结果

    

同理,在创建时间处,如果加入函数执行符,则会立即执行。这时变成了写死的时间

    

 

   接下来设计修改时间文档格式

    

 

   此外还有用户头像avatar,在用户信息设置处有个默认头像

  

 

   

 

   此外,在用户信息设置里还有介绍bio

  

 

   加下来还有性别gender

  

 

   接下来还有生日,生日这里不用加默认值

  

接下来结合业务逻辑需求,看下还需要哪些数据,如下所示

  

 

   

 

   分析完毕后,此外还有账户状态status。例如管理员管理用户状态,禁言、封号等等... ...

  

此外也可以通过mongoose框架模型层次,对数据格式做限制,例如email必须为邮箱格式、昵称nickname长度不能超过10位等等... ...,需要用到验证中间件,后期介绍

  

 

(12)处理注册请求

  1、开启数据库服务,连接数据库

    

  2、基于之前设计的用户数据模型,进行业务操作(注册、登录等)

    注册即为保存数据、登录为查询数据

    在正式操作前,首先在编码里连接数据库

    

 

     目前为止先写到这里,但操作其他数据时(topic.js、comment.js)还需要再次连接,肯定不合适

    所以这里做下修改,新建mongoose.js操作数据库,如下所示

/*1、引包*/
var mongoose = require('mongoose')

var db_url = 'mongodb://localhost/blog'
/*2、连接数据库*/
/*mongoose.connect('mongodb://localhost:27017/0204')默认开启的端口为27017*/
mongoose.connect(db_url)/*这里也可以将端口去掉,默认便是27017*/
/* 链接成功 */
mongoose.connection.on('connected', function() {
  console.log('Mongoose connection open to ' + db_url);
});
/* 链接异常 */
mongoose.connection.on('error', function(error) {
  console.log('Mongoose connection error:' + err);
});
/* 链接断开 */
mongoose.connection.on('disconnected', function() {
  console.log('Mongoose connection disconnected');
});

module.exports = mongoose;

    之后在其他文件调用即可

    

 

     

 

     首先查询用户邮箱是否存在,然后查询用户昵称是否存在。这里我们使用fAPI为indOne,find方法即使只查出一个,也会将其放入数组

    

 

     如果邮箱已经存在,接下来需要判断昵称,查询文档,找到or操作

    

 

     

 

     所以接下来利用or

      

 

     接下来直接判断“邮箱或者昵称是否重复。如果两者有一个存在则提示,邮箱或者昵称已存在”

当然可能有的网站在切换输入框时便直接判断,这样的话需要将邮箱、昵称分开编写API接口

    

注意:这里res.send()返回结果需要结合客户端代码进行分析。
    如下所示,查看后即可得知,该操作是表单操作post异步请求,需要服务端返回JSON数据,之后客户端根据JSON内容进行业务交互

    

    接下来做下测试

    

 

     

此时发现客户端没有输出,服务端执行到了OK。
那么问题来了:服务端发送了响应数据,为什么客户端没有输出呢?(服务端发送了响应数据为ok,如下所示)

    

原因:客户端ajax里指定期望服务器返回数据格式dataType为json,但服务端发送的不是json。所以客户端解析不到,所以客户端没有报错,也看不见
  接下来做下测试,给客户端发送响应数据,格式为json

    

 

     此时在做下测试,点击注册按钮后,便可以发现客户端打印数据

    

分析:jQuery的ajax里的dataType:json的作用为
    预期后台返回结果为json字符串,如果返回的是json字符串,那么直接将其解析转为js可操作的对象,结合文章jQuery的ajax里dataType预期服务器返回数据类型.理解

    如果后台返回结果为字符串,而不是json格式字符串,那么无法进行转换,如下所示

    

 

     如果这里是纯字符串,那么肯定无法正常转换。但客户端里面尝试转换对象格式失败,虽然无法正常输出,但也不会报错

 

  3、后台发送json格式响应

    如下所示,直接发送json格式响应

    

 

     所以这里使用JSON.stringify()进行转换

    

 

     此时注册页面提交后便可以输出后台发送的响应

    

  4、Express框架的json方法

    再在响应里添加数据,测试如下

    

 

 

     

 

 

     都可以正常获取服务器返回响应,但是这样操作也过于繁琐,Express封装了json方法可以直接转换

    

    测试如下:

    

Express的响应方法json方法会自动将里面的对象转换为json字符串,也就免去了手动转换

    小结:

    

  5、json响应方法替换send

    接下来将之前的send响应方法都替换为json,然后统一响应格式.

    

     这里注意:error中属于服务器错误所以success为false,而邮箱或者昵称已经存在属于业务操作,都已经完成对比,所以状态码为200

  6、保存数据到数据库 

    如果数据没有问题,则保存数据到数据库

    

 

 

     接下来做下测试,注册页面填写信息提交,然后连接数据库进行查询

    

    

 

 

     再次点击注册,客户端输出结果如下(邮箱或昵称已存在email or nickname already exist)

    

  7、服务端自定义业务状态码

接下来开始在客户端根据服务端返回响应进行操作,但此时仍然存在问题

    

 

     即返回状态码都为200或者500,无法准确获取响应结果。此时便需要在服务端设计一些自定义的业务状态码... ...

    虽然也可以根据字符message判断,但字符可控性太差,所以还是推荐自定义业务状态码

接下来将success改为error_code,然后自定义值
500为错误,1为邮箱或昵称已存在,0位成功... ...

    

因此这里便需要接口文档进行前后端协同开发,统一规定自定义业务状态码

  8、客户端接收响应,针对性处理

    

 

     测试如下(再次提交时便会提示,信息已经存在)

    

 

    此时可以用CMD或者MongoDB的可视化操作工具进行预览,接下来可以启动预览

    

 

    CMD操作如下

     

 

   9、密码加密md5

    此时可以从数据库直接看到密码,但像密码这种隐私数据,一般存储时都是md5加密(php、node、java等任何语言都可以加密操作)

    目的:防止数据库信息泄露,用户密码曝光

这里便需要用到第三方包,Github有很多种,选择一种即可

 

    

 

    这里例如选择第一个

    

 

     这里附上GitHub中文社区,进入直接搜索md5即可GitHub中文社区

     接下来开始安装使用

    

 

     接下里引入使用

    

 

     然后在存储数据之前对密码进行二次加密,当然也可以多层加密,提高安全性。一层加密的话加密程度低,建议至少两层

    

 

     接下来做下测试(密码为123456)

    

    注册成功后查看数据库,此时发现密码为加密后的数据

    

 

     注意:

登录时输入的密码不能直接和数据库存储的加密密码比对,都是拿着加密的密码进行比对。
且只能正向加密,不能反向解密。所以,即使是开发人员,也无从得知用户密码

 

     

(13)表单同步提交和异步提交

  1、分析

    从特性上将,表单具有默认的提交行为,默认是同步的,即同步表单提交,浏览器会锁死(转圈... ...),等待服务端的响应结果

    接下来做下对比分析

  2、异步提交,首先看下案例里的异步提交

    

 

异步表单提交:form标签内部不再编写action和method,而是通过ajax的url和method选项去实现提交

  3、同步提交

    

     同步提交时不再需要ajax,而是直接在form表单的开始标签里添加action和method属性实现,接下来开始进行注册

    

     点击提交按钮

    

    再次刷新页面,内容如下

    

  4、区别

    同步提交表单内容会导致浏览器锁死,异步提交表单内容不会发生锁死,浏览器任然可以干别的事情

    详情参见文章浅谈表单同步提交和异步提交.

 

(14)服务端重定向,针对异步请求无效

当注册成功后,应该重定向到登录页面

  

 

   目前为止,只是弹框提示

  注意:如果客户端是异步请求,服务端重定向针对异步请求无效。如下所示,如果改为重定向或者res.render()、res.send()都会无效,无法跳转重定向。

  即如果是异步请求服务端无法重定向,对比之前的表单同步请求则可以实现跳转重定向

  

  

   所以如果想实现重定向,必须由客户端实现。如下所示

  

  关于页面重定向知识点,如下所示

  

 

 

 

(15)登录功能

  1、首先编写html模板代码

    

    接下来编写脚本代码,获取表单输入提交内容,并且阻止表单默认提交事件

    

 

     测试如下

    

  2、发送AJAX请求,执行异步提交操作

    注意:一般为了防止他人暴力破解,不会专门提示邮箱错误或者密码错误。

    场景:他人在输入邮箱和密码后提示密码错误,则可以知道,该账号一定存在,接下来只破解密码即可,增加了用户账号风险。如下所示

    

     所以一般会提示“邮箱或者密码错误”,所以编写ajax请求如下

    

  3、处理登录操作服务端

登录界面渲染已经没有问题即get请求已经解决,接下来主要处理表单post请求

    

   4、处理登录post请求

步骤:获取请求数据→查询数据库→发送响应

    

     首先获取表单数据,接下来链接数据库查询,因为之前已经加载过了用户数据设计文档

    

     所以接下来通过User操作即可

    

注意:
    1、可以在读取失败时直接将错误信息发送回去,通过error自带的属性,即error.message属性。此时客户端在开发时,便可以看到详细报错信息
    2、因为是异步请求,服务端无法重定向到首页,所以需要发送成功响应,自定义状态码
    3、用户存在,登录成功,通过Session记录登录状态(稍后添加)

    测试如下

    

     点击确定后便会重定向到首页,接下来做下session登录状态存储。

  

 

(16)通过session保存登录状态

   详见文章node通过session保存登录状态.

 

(17)处理用户退出功能

  接下里编写退出功能,即点击退出按钮时进行用户退出操作

  

 

   

 

   接下来编写路由

  

注意:a链接默认为同步请求,因为点击链接时,浏览器便会刷新。
  因为是同步请求,所以可以使用服务端重定向。注意:之前所讲,ajax异步请求的重定向,无法在服务端操作。

  

  

 

 

 

 

   

(18)小结

  

 

   

 

   

 

   

(19)总结

  

 

   

 

 

 

 

 

 

 

.

 

posted @ 2020-02-07 11:37  剑仙6  阅读(135)  评论(0编辑  收藏  举报
欢迎访问个人网站www.qingchun.在线