【NodeJS】归纳篇(三)Express | 链式操作 | cookie && session | 模板引擎 | Router | mysql

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
云数据库 RDS PostgreSQL,集群系列 2核4GB
简介: 【NodeJS】归纳篇(三)Express | 链式操作 | cookie && session | 模板引擎 | Router | mysql

初步使用

第一步

  • npm install express

示例:server.js

  • 1、创建服务
  • 2、监听
  • 3、处理请求
const express = require('express');
var server = express();//1、创建服务
//3、响应请求
//use() 添加响应
server.use('/a.html',function(req,res){
//req和res是经过express封装过的,并非nodejs中原生的
  res.send('abc');//类似于write()
  res.end();
});
server.use('/b.html',function(req,res){
  res.send('cba');//类似于write()
  res.end();
});
server.listen(8080);//2、监听

3种接收用户请求的方法:

  • get(’/’,function(req,res){});
  • post(’/’,function(req,res){});
  • use(’/’,function(req,res){});//都能接收get和post方式的请求

改进

express-static 处理静态文件的中间件

const express = require('express');
const expressStatic = require('express-static');
var server = express();
server.listen(8080);
//接口:get方式: /login?user=xxx&psw=xxx
//返回: {result:true/false,msg:'原因'}
server.get('/login',function(req,res){
  var user = req.query['user'];
  var psw  = req.query['psw'];
  if(users[user]==null){
    res.send({reslut:false,msg:'不存在'});
  }else {
    if(users[user]!=pass){
      res.send({reslut:false,msg:'密码错了'});
    }else{
      res.send({reslut:true,msg:'成功'});
    }
  }
});
server.use(expressStatic('./www'));//从www这个目录下读取静态文件

处理数据

const express = require('express');
const bodyParser = require('body-parser');
var server = express();
server.listen(8080);
server.use(bodyParser.urlencoded({
  extended: false,  //扩展模式,true启用,false普通模式
  limit: 2*1024*1024         //限制,最大支持的POST数据,默认100k
})); //使用多个use()时,会形成一个链式操作(下面会讲到)
//获取Get,Post相关数据
server.use('/',function(req,res){
  console.log(req.query); //获取Get
  console.log(req.body); 
  //获取Post,需要一个中间环节server.use(bodyParser.urlencoded({}));
});

由此可见:

  • Get无需中间件支持
  • POST需要body-parser中间件,先server.use(bodyParser.urlencoded({})); 后req.body

链式操作

从上节中可以看到链式操作,你可以简单理解使用链式操作是规定这个操作流程有一个步骤,即需要先做什么,然后做什么。依次下去形成一个**“流水线”**。

改写示例:

const express = require('express');
const bodyParser = require('body-parser');
var server = express();
server.listen(8080);
server.use('/',function(req,res,next){//注意参数
  console.log(1);
  next();  //**注意,next()是选择性的执行**
});
server.use('/',function(req,res,next){
  console.log(2);
});

注意到,在use()的参数中,多了一个next,这是一个可选操作,即供用户选择是否要下一步操作。

中间件怎么写——原生

const express = require('express');
const querystring = require('querystring');
var server = express();
server.listen(8080);
server.use(function(req,res,next){//没有第一个参数,则对所有路径请求都接收
//原生写法
  var str = '';
  req.on('data',function(data){
    str+=data;
  });
  req.on('end',function(){
    req.body = querystring.parse(str);  //解析字符串
    next();  //**注意next()所在位置**
  });
});
server.use(function(req,res){
  console.log(req.body);
});

改写,将其写成一个模块mybody-parser.js。

const querystring = require('querystring');
modules.exports={//没有第一个参数,则对所有路径请求都接收
  parser:function(){
    return function(req,res,next){
        var str = '';
        req.on('data',function(data){
          str+=data;
        });
        req.on('end',function(){
          req.body = querystring.parse(str);  //解析字符串
          next();  //注意next()所在位置
        });
      };
  };
};

引用mybody-parser.js模块

const express = require('express');
const mybodyParser = require('mybody-parser');
//mybody-parser输出的是一个function,那么mybodyParser就是一个function
var server = express();
server.listen(8080);
server.use(mybodyParser.parser());//使用mybody-parser中间件
server.use(function(req,res){
  console.log(req.body);
});
  • 其他:
    multer 多文件上传中间件,需求先指定上传后文件的存储位置。

cookie && session

  • cookie : 在浏览器保存一些数据,每次请求都会带过来
    缺陷:不安全、存储空间有限(4k)
  • session : session是逻辑上的,其还是基于cookie实现,也保存数据,但保存在服务端。
    优点:安全、存储空间依据服务器空间。
    原理:客服端请求服务端,先带一个空的cookie={}传到服务端,然后服务端对这个cookie赋值并写到客户端;下一次客户端向服务端发起请求时,就会带上这个cookie。cookie中会有一个session的ID,服务器利用sesssion的ID找到session文件或读取、写入。
    隐患session劫持

读取与发送cookie

  • 读取——cookie-parser
const express = require('express');
const cookieParser = require('cookie-parser');//引入中间件
var server = express();
//cookie
server.use(cookieParser());
server.use('/',function(req,res){
  res.cookie('user','imaginecode',{path:'/www',maxAge:30*24*36000*1000});
  //maxAge:设置过期时间(有效期),单位毫秒
  //path:指定在该路径下可以读这个cookie 
  //读取cookie
  console.log(req.cookies);
});
server.listen(8080);
  • cookie安全性:cookie签名
const express = require('express');
const cookieParser = require('cookie-parser');//引入中间件
var server = express();
//cookie
server.use(cookieParser('imaginecode0101'));
server.use('/',function(req,res){
  req.secret = 'imaginecode0101';//设置密钥
  res.cookie('user','imaginecode',{signed:true});
  //加入参数signed签名,需要提供密钥secret
  console.log("带签名的cookie",req.signedCookies);
  console.log("无签名的cookie",req.cookies);  
});
server.listen(8080); 

注意

cookie空间非常下,要省着用;

安全性差——校验cookie是否被纂改过;

小结

  • res.cookie()//发送cookie
  • 读取cookie:使用到中间件——cookieParser,server.use(cookieParser('密钥'))
  • 用cookie: req.cookies 未签名版,req.signedCookies 带签名
  • 删除cookie: res.clearCookie(cookie名);
  • cookie加密——cookie-encrypter,cookie加密意义不大。

session——cookie-session中间件

1、写入

2、读写

const express = require('express');
const cookieParser = require('cookie-parser');//引入中间件
const cookieSession = require('cookie-session');
var server = express();
//cookie
server.use(cookieParser('imaginecode0101'));
//session
server.use(cookieSession({
  name: 'sess',//session名
  keys = ['aaa','bbb','ccc'],
  //使用session时,需要加keys--密钥,keys为数组,会依次循环使用keys中的密钥对session加密
  //keys密钥数组越长,越安全
  maxAge: 1*3600*1000 //设置有效期1小时
}));
server.use('/',function(req,res){
if(req.session['count']==null){//第一次
  req.session['count']=1;
}else {
  req.session['count']++;
}
    console.log(req.session);//注意session在request上
});
server.listen(8080);

模板引擎

  • jade: 破坏式的、侵入式、强依赖
  • ejs: 温和、非侵入式、弱依赖 (推荐)
  • template.js

jade与ejs对比

  • jade

参考文档:http://jade-lang.com/

const jade = require('jade');
var str = jade.renderFile('a.jade',{pretty:true});
console.log(str);

a.jade

//用缩进代表层级
html
 head
  style
  script
 body
  div
  p  
  • ejs

参考文档:https://ejs.bootcss.com/

ejs.js

const ejs = require('ejs');
ejs.renderFile('a.ejs',{name:'imaginecode'},function(err,data){
  if(err){console.log('编译失败')}
  ekse {console.log(data);}
});

a.ejs

<html>
  <head>
  </head>
  <body>
    {%= name %} //注意变量前后的空格,另外变量name来自ejs.js中
  </body>
</html>

路由-route:一个小型的Express

把不同的目录对应到不同的模块。

  • 假设访问 xxx.com/news ,则调用 mod_news
    子路由 post , 则调用 news_post
  • 访问 xxx.com/users ,则调用 mod_users
    如:
var r1 = express.Router();
var r2 = express.Router();
server.use('/article',r1);//**添加路由时要使用use()
r1.get('/a.html',function(req,res){
  res.send('a.html').end(); //r1用于管理article目录下的a.html
server.use('/comment',r2);
r2.get('/b.html',function(req,res){
  res.send('b.html').end();//r2用于管理comment目下的b.html
});
})

路由多的情况下,使用函数管理。如:

var r1 = createRouter();
function createRouter() {
  var router = express.Router();
  router.get('/a.html',function(req,res){
  res.send('a.html').end();
  });
  router.get('/b.html',function(req,res){
  res.send('b.html').end();
  });
  return router;
}

改进:写成一个模块

/route/createRouterA.js

const express = require('express');
module.exports = function() {
  var router = express.Router();
  router.get('/a.html',function(req,res){
  res.send('a.html').end();
  });
  router.get('/b.html',function(req,res){
  res.send('b.html').end();
  });
  return router;
{

然后进行引入:

server.js

server.use('/article',require('./route/createRouterA.js')());

上面是对artile目录进行操作,同理,可以对comment目录进行相同的操作。

mysql

设计表之前可以先建立数据字典,有一个宏观的参考。

例如:user_table表

ID      
username  用户名       varchar(32)
password  密码        varchar(32)
src       用户头像     varchar(64)

然后建表完成之后,可以进行mysql客户端的操作。

const mysql = require('mysql');//引用mysql模块
//1、连接
//createConnection(服务器名,用户名,密码,数据库名);
var db = mysql.createConnection({
  host:'localhost',
  port:3306,
  user:'root',
  password:'root',
  database:'testdb'
});
//2、查询 query(sql语言,回调函数)
db.query("",(err,data)=>{
  if(err){
    console.log('出错',err);
  }else {
    console.log('成功',data);
  }
});

连接池 (Pool)

保持某个数目的连接数,连接的时候选择能用的连接,避免重复连接

//createPool
const db = mysql.createPool({
  host:'localhost',
  port:3306,
  user:'root',
  password:'root',
  database:'testdb'
});

sql语言-CURD

SQL 标准写法:

1、关键字大写

2、库、表、字段需要加上’’

3、分号结尾

//增-INSERT
// INSERT INTO 表 (字段列表) VALUES(值列表)
INSERT INTO 'user_table' ('ID','username','password') VALUES(0,'imaginecode','123');
//删-DELETE
DELETE FROM 表 where 条件
//改-UPDATE
UPDATE 表 SET 字段=值,字段=值,... WHERE 条件
// 查-SELECT
// SELECT 字段名 FROM 表
SELECT * FROM 'user_table';

字句

  • WHERE 条件
WHERE age<=10
WHERE age>=10 AND score<60
WHERE age>15 OR score>80
  • ORDER 排序
ORDER BY age ASC/DESC
//先按价格升序,再按销量降序
ORDER BY price ASC,sales DESC 
  • GROUP 聚类、合并相同
//按班级分组,将class相同的合并
SELECT class,COUNT(class) FROM student
GROUP BY class
//计算各班平均分
SELECT class,AGE(score) FROM student
GROUP BY class
//计算各班最高分,最低分
SELECT class,MAX(score),MIN(score) FROM student
GROUP BY class
//统计每个人买的数量,按总数升序排列
SELECT name,SUM(price) FROM sales_table GROUP BY name ORDER BY SUM(price) ASC
  • LIMIT-限制输出

应用:分页。

分页的方式

1、所有数据一次性传给前端;不适合数据量大的情况。

2、每次后台只给一页数据给前端;

写法:

LIMIT 10;要10条

LIMIT 2,8;从第二条开始,要8个

注意:字句之间有顺序:

WHERE, GROUP BY, ORDER BY, LIMIT

如:

SELECT class,COUNT(class) FROM student
WHERE score>60
GROUP BY COUNT(class) DESC
LIMIT 2;

至此,归纳了Express的基础使用,以及对模板引擎进行归纳。


相关实践学习
如何快速连接云数据库RDS MySQL
本场景介绍如何通过阿里云数据管理服务DMS快速连接云数据库RDS MySQL,然后进行数据表的CRUD操作。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
11天前
|
存储 前端开发 Java
【SpringMVC】——Cookie和Session机制
获取URL中参数@PathVarible,上传文件@RequestPart,HttpServerlet(getCookies()方法,getAttribute方法,setAttribute方法,)HttpSession(getAttribute方法),@SessionAttribute
|
2月前
|
存储 安全 搜索推荐
理解Session和Cookie:Java Web开发中的用户状态管理
理解Session和Cookie:Java Web开发中的用户状态管理
81 4
|
2月前
|
存储 缓存 网络协议
计算机网络常见面试题(二):浏览器中输入URL返回页面过程、HTTP协议特点,GET、POST的区别,Cookie与Session
计算机网络常见面试题(二):浏览器中输入URL返回页面过程、HTTP协议特点、状态码、报文格式,GET、POST的区别,DNS的解析过程、数字证书、Cookie与Session,对称加密和非对称加密
|
3月前
|
缓存 Java Spring
servlet和SpringBoot两种方式分别获取Cookie和Session方式比较(带源码) —— 图文并茂 两种方式获取Header
文章比较了在Servlet和Spring Boot中获取Cookie、Session和Header的方法,并提供了相应的代码实例,展示了两种方式在实际应用中的异同。
225 3
servlet和SpringBoot两种方式分别获取Cookie和Session方式比较(带源码) —— 图文并茂 两种方式获取Header
|
3月前
|
存储 安全 数据安全/隐私保护
Cookie 和 Session 的区别及使用 Session 进行身份验证的方法
【10月更文挑战第12天】总之,Cookie 和 Session 各有特点,在不同的场景中发挥着不同的作用。使用 Session 进行身份验证是常见的做法,通过合理的设计和管理,可以确保用户身份的安全和可靠验证。
43 1
|
4月前
|
存储 缓存 数据处理
php学习笔记-php会话控制,cookie,session的使用,cookie自动登录和session 图书上传信息添加和修改例子-day07
本文介绍了PHP会话控制及Web常用的预定义变量,包括`$_REQUEST`、`$_SERVER`、`$_COOKIE`和`$_SESSION`的用法和示例。涵盖了cookie的创建、使用、删除以及session的工作原理和使用,并通过图书上传的例子演示了session在实际应用中的使用。
php学习笔记-php会话控制,cookie,session的使用,cookie自动登录和session 图书上传信息添加和修改例子-day07
|
3月前
|
SQL JavaScript 关系型数据库
Node.js 连接 MySQL
10月更文挑战第9天
42 0
|
4月前
|
存储 前端开发 Java
JavaWeb基础7——会话技术Cookie&Session
会话技术、Cookie的发送和获取、存活时间、Session钝化与活化、销毁、用户登录注册“记住我”和“验证码”案例
JavaWeb基础7——会话技术Cookie&Session
|
4月前
|
存储 安全 NoSQL
Cookie、Session、Token 解析
Cookie、Session、Token 解析
84 0
|
5月前
|
存储 JavaScript 前端开发
Cookie 反制策略详解:Cookie加解密原理、Cookie和Session机制、Cookie hook、acw_sc__v2、jsl Cookie调试、重定向Cookie
Cookie 反制策略详解:Cookie加解密原理、Cookie和Session机制、Cookie hook、acw_sc__v2、jsl Cookie调试、重定向Cookie
324 1