Node中的一些概念和中间件的介绍

一、搭建基本服务器

  1. 引入两个模块:http、fs
  2. 创建http对象,监听端口
  3. 引入url、querystring模块
  4. 处理静态文件请求、接收动态数据

二、模块化开发

  1. 模块化的意义:形成局部作用域,不会污染全局变量

    • commonJS:node、webpack是其规范的实现
    • node不支持ES6的模块化,但支持所有的ES6+语法
    • 可以通过typescript转化,在node中使用ES6模块化
  2. 批量导出可输出多次

    • exports.属性1 = 值1
    • exports.属性2 = 值2
    • 导出的都是属性,可导出任何类型的值
    • 但导入的只是对象,通过对象的属性执行
  3. 默认导出只输出一次

    • 默认导出只输出第一个值
    • module.exports = [a,b]
    • module.exports = {a,b}
    • 当批量导出和默认导出同时存在,只输出默认导出
    • 且下面的默认输出会覆盖上面的默认输出语句
    • 可以导出任何类型,导出什么类型,引入的就是什么类型
  4. 引入的类型跟输出形式有关

    • 批量导出,引入的都是对象
      • 引入对象:const module = require("路径")
      • 按需使用,引入对象身上的属性
        • const module = require("路径").属性
    • 默认导出,与引入类型相同
      • const module = require("路径")[i]
      • const module = require("路径").属性
    • 没有导出,引入的就是空对象
    • 引入路径:支持任何类型
      • 不指定路径:先找系统模块 -> 再从项目环境找node_modules|bower_components(依赖模块) -> not found
      • 指定路径:找指定路径 -> not found
  5. 模块化代码执行

    • 模块里的代码从引入的那一行开始执行
    • 导出的值从引入后调用的那一行开始执行

三、express

  1. 包管理工具:npm、yarn、bower

  2. 接口响应

    • 支持各种请求方式:get、post、put、delete...
      app.请求姿势API(接口名称,处理函数)
      app.get(url,(req,res,next)=>{})
      app.post(url,(req,res,next)=>{})
      ...
    
  3. app.use():传入中间件到app实例

    • 安装中间件、路由,接受一个函数
    • use响应所有的请求姿势(get,post,...)
      // app.use([地址],中间件|路由|函数体)
      // 地址 "/" 可省略
      app.listen("3000","主机",()=>{});
      app.use(express.static("./www"));
      app.use(bodyParser());
    
  4. app.all():处理子管道的共同业务

      app.all("/admin/*",(req,res,next)=>{
        next() // 管道流,流入下一管道
      })
      // all匹配全路径 处理所有HTTP 
      // 需要next()延续后续
    
  5. 动态接口:admin/:ab/:abc

    • 响应动态url接口地址
    • ~/admin/abc/dadc
    • ~/admin/s12/acs33
  6. 请求体/request

      req.query  // 获取地址栏的数据
      req.body   // 获取非地址栏的数据  依赖中间件 
      // req.body依赖中间件:body-parser
      req.params // 获取动态接口名
      req.method // 获取前端提交方式
    
  7. 响应体/response

      res.send(any) // 对等 res.write + end
      res.end(string|buffer)
      res.json(json) // 返回json
      res.status(404).send() // 返回状态和信息
      res.jsonp(响应数据) // 调用请求时的回调函数并传递响应数据
      res.sendFile(path.resolve('public/error.html')) // 渲染纯 HTML 文件
      // 上部引入const path = require("path");
    
  8. jsonp响应

      app.set('jsonp callback name','回调函数名') // 默认callback
      app.get('/jsonp接口',(req,res,next)=>res.jsonp(数据))
    
  9. 中间件

    • middleware,处理自定义业务,只处理请求到结束响应的中间部分
      // npm i body-parser -S // 安装包
      let bodyParser=require('body-parser') // 引入中间件
      app.use(bodyParser()) // 安装中间件
    
  10. 后端跳转

      app.get("/api/old", (req, res, next) => {
        res.redirect("/api/new");
      })
      // res.redirect(url) // 指向一个接口
      app.get("/api/new", (req, res) => {
        console.log("这是新业务");
      })
    

四、身份验证

(一)session

  1. 客户端用户名跟密码请求登录
  2. 服务端收到请求,去库验证用户名与密码
  3. 验证成功后,服务端种一个cookie或发一个字符到客户端,同时服务器保留一份session
  4. 客户端收到 响应 以后可以把收到的字符存到cookie
  5. 客户端每次向服务端请求资源的cookie会自动携带
  6. 服务端收到请求,然后去验证cookie和session,如果验证成功就向客户端返回请求的库数据

Session存储位置:服务器内存,磁盘,或者数据库里
Session存储内容:id,存储时间,用户名等说明一下登录的用户是谁
客户端携带:cookie自动带,localStorage手动带

如何保存信息给浏览器

  • 前端种:
    • cookie/localstorage
  • 后端种:
    1. 服务器给浏览器种cookie: cookie-parser,只种cookie,不留session
    2. 服务器给浏览器种cookie的同时在服务器上生成seesion: cookie-session

cookie-session

  // 安装并引入cookie-session
  const cookieSession = require('cookie-session');

  // 配置中间件
  app.use(cookieSession({
    name: "test_session", // 保存到服务器的session的名字
    keys: ["a", "b", "c"], // [必传参数,代表加密层级]
    maxAge:1000 //保留cookie的时间,ms
  }));

  // 种cookie,备份session
  req.session.key=value;

  // 删除cokkie、session
  delete req.session.key;
  req.session.key = undefined;

(二)token

  • 在服务端不需要存储用户的登录记录,全部发给客户端有客户端自己存(cookie,local)
  1. 客户端使用用户名跟密码请求登录
  2. 服务端收到请求,去验证用户名与密码
  3. 验证成功后,服务端会签发一个 Token(加了密的字符串),再把这个 Token 发送给客户端
  4. 客户端收到 Token 以后可以把它存储起来,比如放在 Cookie 里或者 Local Storage 里
  5. 客户端每次向服务端请求资源的时候需要带着服务端签发的 Token
  6. 服务端收到请求,然后去验证客户端请求里面带着的 Token,如果验证成功,就向客户端返回请求的数据

token的实现

  // 安装并引入jsonwebtoken
  const jwt = require('jsonwebtoken');

  // 生成token,返回给客户端 --- 异步回调函数
  // jwt.sign({username,id:"db_id"},"test_token",(err,token)=>{
  //   if(!err) res.send({err:0,msg:"登录成功",data:[],token});
  // });
  // 生成token,同步获取
  let token = jwt.sign({username,id:"db_id"},"test_token");
  res.send({err:0,msg:"登录成功",data:[],token});

  // 获取客户端发送的token
  let token = req.headers.token || req.query.token || req.body.token;
  console.log(token);

  // 校验token
  jwt.verify(token,"test_token",(err,decode)=>{
    if(err){
      res.send({err:2,msg:"token校验失败",data:"no data"});
    }else{
      res.send({err:1,msg:"token校验成功",data:[]});
    }
  });

  // 注销,删除token前端完成

(三)两者区别

  1. session需要在用户端保存信息;
  2. token能够避免CSRF攻击;
  3. token的安全性更高;
  4. session存在多服务器粘性问题。

五、文件上传

  1. 思想:前端表单->后端接收到文件本身->保存到服务器上->给数据库记录文件一些信息->库返回给nodejs相关信息->nodejs返回给前端

      <!-- 前端 -->
      <input type=file enctype="multipart/form-data" name="fieldname">
    
  2. 实现:multer->文件名会随机->fs模块改名->path系统模块解析磁盘路径

    • 后端:multer 接受 form-data编码数据

(一)path模块

  1. 操作系统磁盘路径

  2. 编码

    • windows:c:\\user\\admin\\a.jpg
    • mac:~/desktop/1901
  3. UI呈现

    • windows: c:\user\admin
    • mac: ~/desktop/1901
  4. API

    • 磁盘路径解析 parse

        // string -> object
        // path.parse('c:\\wamp\\xx.png')
        path.parse('./wamp/xx.png')
        //返回
        {
          root: 'c:\\', 盘符
          dir: 'c:\\wamp', 目录
          base: 'xx.png',  文件名
          ext: '.png', 扩展名
          name: 'xx'    文件,不含扩展名
        }
      
    • 片段合并 join

      • path.join('磁盘路径1','磁盘路径2','磁盘路径n')
      • __dirname 全局|魔术变量 返回当前文件所在的磁盘路径
    • 片段合并 resolve

      • path.resolve('磁盘路径1','磁盘路径n')
      • 合并磁盘片段,从右到左找根,找到从当前向右拼接,没有找到根,以当前文件路径为根

(二)multer中间件

  1. multer 接受 form-data编码数据,所有要求前端携带时应注意

    • 如:<input type=file enctype="multipart/form-data" name="icon">
  2. 使用

      //1 引入
      let multer  = require('multer');
      //2 实例化  
      let objMulter = multer({ dest: './upload' }); //dest: 指定 保存位置(存到服务器)
      //安装中间件
      app.use(objMulter.any());  //允许上传什么类型文件,any 代表任何类型 
    
  3. 中间件扩展了req请求体 req.files

      app.get('/reg',(req,res)=>{
        req.files // 多个文件
        // req.file // 单个文件
      })
    
      fieldname: 表单name名
      originalname: 上传的文件名
      encoding: 编码方式
      mimetype: 文件类型
      buffer: 文件本身
      size:尺寸
      destination: 保存路径
      filename: 保存后的文件名  不含后缀
      path: 保存磁盘路径+保存后的文件名 不含后缀
    

六、后端渲染

  1. 通常根据后端返回的json数据,然后来生成html被称为前端渲染,而后端渲染是后端把json与html结合渲染好后返回到浏览器,没前端什么事了

  2. 模板引擎

    • 无论前后谁来渲染页面,都会用到模板引擎,前端渲染页面实际上是操作dom,后端渲染页面是把数据和html字符拼接后丢给浏览器

(一)jade

  1. 使用

      let jade = require('jade')
      let html = jade.renderFile('jade模板文件',{数据},{pretty:true});    //返回字符
    
  2. jade语法

    • 父子要缩进
    • 属性:标签(key=value,key2=value)
    • 内容: 标签 内容
  3. 其他扩展

(二)ejs

  1. 使用

      let ejs = require('ejs')
      ejs.renderFile('ejs模板文件',{要合并到html数据},回调(err,data))
      // err:错误,null代表没有错误
      // data:渲染后的字符|流  
      // ejs模板:后缀名为ejs的html文件
    
  2. ejs语法

    • ejs 结构就是html
    • 输出: <%= 数据名|属性名|变量名 + 表达式 %>
    • 语句: <% 语句 %> 需要被<% %> 包裹
    • 非转义输出: <%- 数据名|变量名 + 表达式 %>
    • 载入公共:<%- include('./hd.ejs',{数据}) %>
  3. 其他扩展

七、路由

  1. 告诉你去哪,对于前端,主要是导向,告诉浏览器应该去哪,对于后端,可以理解为一个子服务,一个路由就是一个小的服务(server/app)模块,处理一个接口

  2. 配置和使用

    • 创建模块文件:/router/xx.js
        // 1.创建路由
        let router = express.Router(); 
      
        // 2.路由处理响应
        router.响应API(地址, 处理函数);
      
        // 3.导出路由
        module.exports = router;
      
    • 主服务:/app.js
        //安装路由
        app.use('地址',router); 
      
    • 子路由/子服务/子模块:/router/xx.js
        //子路由里安装路由 嵌套
        router.use('地址',子router) 
      
        //截获当前路由下的部分公共业务
        router.all('*',当前router路由下的验证工作) //需要next 延续
      
    • 主路由的地址对应子路由的根
      • 如:app.js: /api/user ~~ user.js: /
      • 如:app.js: /api/user/add ~~ user.js: /add

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,826评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,968评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,234评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,562评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,611评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,482评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,271评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,166评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,608评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,814评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,926评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,644评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,249评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,866评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,991评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,063评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,871评论 2 354

推荐阅读更多精彩内容