Node实践总结3——routes

来源:互联网 发布:知乎男士商务皮鞋 编辑:程序博客网 时间:2024/06/05 19:03

routes

一个传统的网站往往会有许多路径(/,/login,/user),不同的路径对应不同的页面,有不同的处理逻辑,涉及表单的页面往往还会同时存在getpost两种形式的请求,其往往也承担了核心的业务。


routes结构

GET

先摘一段我工程的代码举个例子:

router.get('/', async function (ctx, next) {  await ctx.render('index', {    title: 'OA',    user: ctx.session.user  });});router.get('/reg', async function (ctx, next) {  await ctx.render('reg', {    title: 'OA-注册'  });});router.get('/login', async function (ctx, next) {  await ctx.render('login', {    title: 'OA-登录'  });});router.get('/logout', async function (ctx, next) {  ctx.session.user = null;  return ctx.redirect('/');});router.get('/user_app', async function (ctx, next) {  await ctx.render('user_app', {    title: 'OA-应用角色管理'  });});router.get('/user_db', async function (ctx, next) {  await ctx.render('user_db', {    title: 'OA-数据库角色管理'  });});router.get('/waf_log', async function (ctx, next) {  var wafLogs = await WafLogs.fetchAll();//从数据库中查询所有的日志信息  var logs = {};  for(var i = 0;i < wafLogs.length;i++){    logs[i] = wafLogs.models[i].attributes;  }  await ctx.render('waf_log', {    title: 'OA-waf日志',    logs: logs  });});

这一部分基本都是简单的get页面的请求,koa使用ctx.render(模板名,{模板需要的变量})做页面渲染,第一个参数指定要使用哪一个模板文件作为返回的页面,第二个参数用于传入变量给jade模板使用。

GET请求时,通常需要服务器返回一个静态页面,所以逻辑都还算比较简单,只需要指定好页面模板和相应的变量即可。

上述例子中,有一个GET /waf_log的route比较特别,这一个get请求需要服务器先查询存放日志的数据库,将日志信息保存成json格式,再由render函数传给模板进行渲染,下面将这一部分前后端的关键代码放在一起对比的看一下。

//后端router.get('/waf_log', async function (ctx, next) {  var wafLogs = await WafLogs.fetchAll();//从数据库中查询所有的日志信息  var logs = {};  for(var i = 0;i < wafLogs.length;i++){    logs[i] = wafLogs.models[i].attributes;  }  await ctx.render('waf_log', {    title: 'OA-waf日志',    logs: logs  });});
//前端doctype htmlhtml  head    meta(charset='utf-8')    title= title    link(rel='stylesheet' href='http://cdn.static.runoob.com/libs/bootstrap/3.3.7/css/bootstrap.min.css')    link(rel='stylesheet' href='/stylesheets/mycss.css')    script(src='http://cdn.static.runoob.com/libs/jquery/2.1.1/jquery.min.js')    script(src='http://cdn.static.runoob.com/libs/bootstrap/3.3.7/js/bootstrap.min.js')body    div.container      div.row        ul.list-inline          li.col-lg-3.nonpadding            p.content-title WAF日志          li.col-lg-6.nonpadding          li.float-right.col-lg-3.nonpadding            div.input-group              input#searchBox.form-control(type='text',placeholder='输入关键字,支持模糊查询',required)              span.input-group-btn                input.btn.btn-warning.btn-search(type='submit',value='搜索')       div#table.row        table.table          thead            tr              th 序号(id)              th 时间(time)              th 用户名(username)              th 访问的功能(function              th 访问的URL(url)              th 参数(param)              th 操作结果(result)          tbody            each log in logs              tr              each val in log                td #{val} 

可以看到后端传给模板两个参数{title: 'OA-waf日志',logs: logs}
模板中title= title,说明前端页面中<title>标签内容是一个变量,值是传入的title参数的值,
模板中tbody下是两个each循环,用于将传入的logs解析出来,动态的生成表格。

asyncawait是ES7标准中用于处理异步操作的关键字,async声明的函数A中可以使用await调用别的函数B,并等到函数B返回之后继续执行A剩余的部分。

ctx是koa2中包装reqres的对象。

next用于链式操作,指代当前函数的下一个函数,常常通过await next()调用。


POST

下面这一部分的routes相对复杂一些:

router.post('/reg', async function (ctx, next) {  if(ctx.request.body['username'].length > 25) {    //判断用户名是否过长,数据库设置username字段为varchar(25)    await ctx.render('reg', {      title: 'OA-注册',      error: '用户名不得超过25个字符'    });  } else if(ctx.request.body['password2'] !== ctx.request.body['password']) {    //判断两次密码是否一致    console.log('两次密码不一致');    await ctx.render('reg', {      title: 'OA-注册',      error: '两次密码不一致'    });  } else {    //判断用户名是否存在    var count = await Users.where('username', ctx.request.body['username']).count('username');    if(count != 0) {      console.log('用户名已存在!');      await ctx.render('reg', {        title: 'OA-注册',        error: '用户名已存在'      });    } else {      var hmac = crypto.createHmac('sha256', 'liuyueyi');      var password = hmac.update(ctx.request.body['password']).digest('hex');      console.log(password);      console.log(password.length);      var newUser = new Users({        username: ctx.request.body['username'],        password: password      });      await newUser.save();      console.log('注册成功,可以直接登录!');      ctx.session.user = newUser;      await ctx.render('reg', {        title: 'OA-注册',        success: '注册成功,可以直接登录'      });      return ctx.redirect('/login');    }  }});router.post('/login', async function (ctx, next) {  //需要判断的逻辑:用户名不存在或者密码错误  var count = await Users.where('username', ctx.request.body['username']).count('username');  if(count == 0) {    console.log('用户名不存在!');    await ctx.render('login', {      title: 'OA-登录',      error: '用户名不存在'    });  } else {    var hmac = crypto.createHmac('sha256', 'liuyueyi');    var password = hmac.update(ctx.request.body['password']).digest('hex');    var user = await Users.where('username', ctx.request.body['username']).fetch();    if (user.attributes.password == password) {      console.log('登陆成功!'+ user.attributes.username);      ctx.session.user = user.attributes.username;      return ctx.response.redirect('/');    } else {      console.log('密码错误!');      await ctx.render('login', {        title: 'OA-登录',        error: '密码错误'      });    }  }});

这一部分是处理前端post回来的表单数据的逻辑代码。


render和redirect

上面的代码中,页面切换使用到了两种方法

  • render
  • redirect

二者是有区别的。

render用于页面渲染,是将指定的模板通过引擎转换成html之后直接画在当前页面之上,如果render指定的模板和当前页不同,地址栏上可以清晰的看见路径没有变化。
redirect则是用于页面跳转,服务器端的后台可以看到跳转的时候响应码是302,并且地址栏的路径也会变化。


AJAX

这一部分我之后单独写。


routes代码可以直接写在app.js当中,但是当业务越来越复杂,页面越来越多的时候,app.js会变得很长,从而不易维护,所以正确的做法是将其移到routes路径下,做成一个模块,使用的时候导入到app.js中。

0 0