前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Node 概念及中间件

Node 概念及中间件

原创
作者头像
大发明家
发布2021-12-15 15:34:36
5.5K0
发布2021-12-15 15:34:36
举报
文章被收录于专栏:技术博客文章

二、模块化开发

  1. 模块化的意义:形成局部作用域,不会污染全局变量
代码语言:txt
复制
* commonJS:node、webpack是其规范的实现
* node不支持ES6的模块化,但支持所有的ES6+语法
* 可以通过typescript转化,在node中使用ES6模块化批量导出可输出多次
代码语言:txt
复制
* `exports.属性1 = 值1`
* `exports.属性2 = 值2`
* 导出的都是属性,可导出任何类型的值
* 但导入的只是对象,通过对象的属性执行默认导出只输出一次
代码语言:txt
复制
* 默认导出只输出第一个值
* `module.exports = [a,b]`
* `module.exports = {a,b}`
* 当批量导出和默认导出同时存在,只输出默认导出
* 且下面的默认输出会覆盖上面的默认输出语句
* 可以导出任何类型,导出什么类型,引入的就是什么类型引入的类型跟输出形式有关
代码语言:txt
复制
* 批量导出,引入的都是对象 
  * 引入对象:`const module = require("路径")`
  * 按需使用,引入对象身上的属性 
    * `const module = require("路径").属性`
* 默认导出,与引入类型相同 
  * `const module = require("路径")[i]`
  * `const module = require("路径").属性`
* 没有导出,引入的就是空对象
* 引入路径:支持任何类型 
  * 不指定路径:先找系统模块 -> 再从项目环境找node_modules|bower_components(依赖模块) -> not found
  * 指定路径:找指定路径 -> not found模块化代码执行
代码语言:txt
复制
* 模块里的代码从引入的那一行开始执行
* 导出的值从引入后调用的那一行开始执行

三、express

  1. 包管理工具:npm、yarn、bower
  2. 接口响应
代码语言:txt
复制
* 支持各种请求方式:get、post、put、delete...
代码语言:txt
复制
      app.请求姿势API(接口名称,处理函数)
代码语言:txt
复制
  app.get(url,(req,res,next)=>{})
代码语言:txt
复制
  app.post(url,(req,res,next)=>{})
代码语言:txt
复制
  ...
  1. app.use():传入中间件到app实例
代码语言:txt
复制
* 安装中间件、路由,接受一个函数
* use响应所有的请求姿势(get,post,...)
代码语言:txt
复制
      // app.use([地址],中间件|路由|函数体)
代码语言:txt
复制
  // 地址 "/" 可省略
代码语言:txt
复制
  app.listen("3000","主机",()=>{});
代码语言:txt
复制
  app.use(express.static("./www"));
代码语言:txt
复制
  app.use(bodyParser());
  1. app.all():处理子管道的共同业务
代码语言:txt
复制
      app.all("/admin/*",(req,res,next)=>{
代码语言:txt
复制
    next() // 管道流,流入下一管道
代码语言:txt
复制
  })
代码语言:txt
复制
  // all匹配全路径 处理所有HTTP 
代码语言:txt
复制
  // 需要next()延续后续
  1. 动态接口:admin/:ab/:abc
代码语言:txt
复制
* 响应动态url接口地址
* `~/admin/abc/dadc`
* `~/admin/s12/acs33`请求体/request
代码语言:txt
复制
      req.query  // 获取地址栏的数据
代码语言:txt
复制
  req.body   // 获取非地址栏的数据  依赖中间件 
代码语言:txt
复制
  // req.body依赖中间件:body-parser
代码语言:txt
复制
  req.params // 获取动态接口名
代码语言:txt
复制
  req.method // 获取前端提交方式
  1. 响应体/response
代码语言:txt
复制
      res.send(any) // 对等 res.write + end
代码语言:txt
复制
  res.end(string|buffer)
代码语言:txt
复制
  res.json(json) // 返回json
代码语言:txt
复制
  res.status(404).send() // 返回状态和信息
代码语言:txt
复制
  res.jsonp(响应数据) // 调用请求时的回调函数并传递响应数据
代码语言:txt
复制
  res.sendFile(path.resolve('public/error.html')) // 渲染纯 HTML 文件
代码语言:txt
复制
  // 上部引入const path = require("path");
  1. jsonp响应
代码语言:txt
复制
      app.set('jsonp callback name','回调函数名') // 默认callback
代码语言:txt
复制
  app.get('/jsonp接口',(req,res,next)=>res.jsonp(数据))
  1. 中间件
代码语言:txt
复制
* middleware,处理自定义业务,只处理请求到结束响应的中间部分
代码语言:txt
复制
      // npm i body-parser -S // 安装包
代码语言:txt
复制
  let bodyParser=require('body-parser') // 引入中间件
代码语言:txt
复制
  app.use(bodyParser()) // 安装中间件
  1. 后端跳转
代码语言:txt
复制
      app.get("/api/old", (req, res, next) => {
代码语言:txt
复制
    res.redirect("/api/new");
代码语言:txt
复制
  })
代码语言:txt
复制
  // res.redirect(url) // 指向一个接口
代码语言:txt
复制
  app.get("/api/new", (req, res) => {
代码语言:txt
复制
    console.log("这是新业务");
代码语言:txt
复制
  })

四、身份验证

(一)session

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

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

如何保存信息给浏览器
  • 前端种:
    • cookie/localstorage
  • 后端种:
    1. 服务器给浏览器种cookie: cookie-parser,只种cookie,不留session
    2. 服务器给浏览器种cookie的同时在服务器上生成seesion: cookie-session
cookie-session
代码语言:txt
复制
  // 安装并引入cookie-session
代码语言:txt
复制
  const cookieSession = require('cookie-session');
代码语言:txt
复制
  // 配置中间件
代码语言:txt
复制
  app.use(cookieSession({
代码语言:txt
复制
    name: "test_session", // 保存到服务器的session的名字
代码语言:txt
复制
    keys: ["a", "b", "c"], // [必传参数,代表加密层级]
代码语言:txt
复制
    maxAge:1000 //保留cookie的时间,ms
代码语言:txt
复制
  }));
代码语言:txt
复制
  // 种cookie,备份session
代码语言:txt
复制
  req.session.key=value;
代码语言:txt
复制
  // 删除cokkie、session
代码语言:txt
复制
  delete req.session.key;
代码语言:txt
复制
  req.session.key = undefined;

(二)token

  • 在服务端不需要存储用户的登录记录,全部发给客户端有客户端自己存(cookie,local)
  1. 客户端使用用户名跟密码请求登录
  2. 服务端收到请求,去验证用户名与密码
  3. 验证成功后,服务端会签发一个 Token(加了密的字符串),再把这个 Token 发送给客户端
  4. 客户端收到 Token 以后可以把它存储起来,比如放在 Cookie 里或者 Local Storage 里
  5. 客户端每次向服务端请求资源的时候需要带着服务端签发的 Token
  6. 服务端收到请求,然后去验证客户端请求里面带着的 Token,如果验证成功,就向客户端返回请求的数据
token的实现
代码语言:txt
复制
  // 安装并引入jsonwebtoken
代码语言:txt
复制
  const jwt = require('jsonwebtoken');
代码语言:txt
复制
  // 生成token,返回给客户端 --- 异步回调函数
代码语言:txt
复制
  // jwt.sign({username,id:"db_id"},"test_token",(err,token)=>{
代码语言:txt
复制
  //   if(!err) res.send({err:0,msg:"登录成功",data:[],token});
代码语言:txt
复制
  // });
代码语言:txt
复制
  // 生成token,同步获取
代码语言:txt
复制
  let token = jwt.sign({username,id:"db_id"},"test_token");
代码语言:txt
复制
  res.send({err:0,msg:"登录成功",data:[],token});
代码语言:txt
复制
  // 获取客户端发送的token
代码语言:txt
复制
  let token = req.headers.token || req.query.token || req.body.token;
代码语言:txt
复制
  console.log(token);
代码语言:txt
复制
  // 校验token
代码语言:txt
复制
  jwt.verify(token,"test_token",(err,decode)=>{
代码语言:txt
复制
    if(err){
代码语言:txt
复制
      res.send({err:2,msg:"token校验失败",data:"no data"});
代码语言:txt
复制
    }else{
代码语言:txt
复制
      res.send({err:1,msg:"token校验成功",data:[]});
代码语言:txt
复制
    }
代码语言:txt
复制
  });
代码语言:txt
复制
  // 注销,删除token前端完成

(三)两者区别

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

五、文件上传

  1. 思想:前端表单->后端接收到文件本身->保存到服务器上->给数据库记录文件一些信息->库返回给nodejs相关信息->nodejs返回给前端
代码语言:txt
复制
      <!-- 前端 -->
代码语言:txt
复制
  <input type=file enctype="multipart/form-data" name="fieldname">
  1. 实现:multer->文件名会随机->fs模块改名->path系统模块解析磁盘路径
代码语言:txt
复制
* 后端:multer 接受 form-data编码数据

(一)path模块

  1. 操作系统磁盘路径
  2. 编码
代码语言:txt
复制
* windows:`c:\\user\\admin\\a.jpg`
* mac:`~/desktop/1901`UI呈现
代码语言:txt
复制
* windows: `c:\user\admin`
* mac: `~/desktop/1901`
代码语言:txt
复制
* 磁盘路径解析 **parse**
    
代码语言:txt
复制
              // string -> object
代码语言:txt
复制
      // path.parse('c:\\wamp\\xx.png')
代码语言:txt
复制
      path.parse('./wamp/xx.png')
代码语言:txt
复制
      //返回
代码语言:txt
复制
      {
代码语言:txt
复制
        root: 'c:\\', 盘符
代码语言:txt
复制
        dir: 'c:\\wamp', 目录
代码语言:txt
复制
        base: 'xx.png',  文件名
代码语言:txt
复制
        ext: '.png', 扩展名
代码语言:txt
复制
        name: 'xx'    文件,不含扩展名
代码语言:txt
复制
      }
代码语言:txt
复制
* 片段合并 **join**
代码语言:txt
复制
  * `path.join('磁盘路径1','磁盘路径2','磁盘路径n')`
  * `__dirname 全局|魔术变量 返回当前文件所在的磁盘路径`
* 片段合并 **resolve**
代码语言:txt
复制
  * `path.resolve('磁盘路径1','磁盘路径n')`
  * 合并磁盘片段,从右到左找根,找到从当前向右拼接,没有找到根,以当前文件路径为根

(二)multer中间件

  1. multer 接受 form-data编码数据,所有要求前端携带时应注意
代码语言:txt
复制
* 如:`<input type=file enctype="multipart/form-data" name="icon">`使用
代码语言:txt
复制
      //1 引入
代码语言:txt
复制
  let multer  = require('multer');
代码语言:txt
复制
  //2 实例化  
代码语言:txt
复制
  let objMulter = multer({ dest: './upload' }); //dest: 指定 保存位置(存到服务器)
代码语言:txt
复制
  //安装中间件
代码语言:txt
复制
  app.use(objMulter.any());  //允许上传什么类型文件,any 代表任何类型 
  1. 中间件扩展了req请求体 req.files
代码语言:txt
复制
      app.get('/reg',(req,res)=>{
代码语言:txt
复制
    req.files // 多个文件
代码语言:txt
复制
    // req.file // 单个文件
代码语言:txt
复制
  })
代码语言:txt
复制
      fieldname: 表单name名
代码语言:txt
复制
  originalname: 上传的文件名
代码语言:txt
复制
  encoding: 编码方式
代码语言:txt
复制
  mimetype: 文件类型
代码语言:txt
复制
  buffer: 文件本身
代码语言:txt
复制
  size:尺寸
代码语言:txt
复制
  destination: 保存路径
代码语言:txt
复制
  filename: 保存后的文件名  不含后缀
代码语言:txt
复制
  path: 保存磁盘路径+保存后的文件名 不含后缀

六、后端渲染

  1. 通常根据后端返回的json数据,然后来生成html被称为前端渲染,而后端渲染是后端把json与html结合渲染好后返回到浏览器,没前端什么事了
  2. 模板引擎
代码语言:txt
复制
* 无论前后谁来渲染页面,都会用到模板引擎,前端渲染页面实际上是 **操作dom** ,后端渲染页面是 **把数据和html字符拼接** 后丢给浏览器

(一)jade

  1. 使用
代码语言:txt
复制
      let jade = require('jade')
代码语言:txt
复制
  let html = jade.renderFile('jade模板文件',{数据},{pretty:true});    //返回字符
  1. jade语法
代码语言:txt
复制
* 父子要缩进
* 属性:标签(key=value,key2=value)
* 内容: 标签 内容

(二)ejs

  1. 使用
代码语言:txt
复制
      let ejs = require('ejs')
代码语言:txt
复制
  ejs.renderFile('ejs模板文件',{要合并到html数据},回调(err,data))
代码语言:txt
复制
  // err:错误,null代表没有错误
代码语言:txt
复制
  // data:渲染后的字符|流  
代码语言:txt
复制
  // ejs模板:后缀名为ejs的html文件
  1. ejs语法
代码语言:txt
复制
* ejs 结构就是html
* 输出: <%= 数据名|属性名|变量名 + 表达式 %>
* 语句: <% 语句 %> 需要被<% %> 包裹
* 非转义输出: <%- 数据名|变量名 + 表达式 %>
* 载入公共:<%- include('./hd.ejs',{数据}) %>

七、路由

  1. 告诉你去哪,对于前端,主要是导向,告诉浏览器应该去哪,对于后端,可以理解为一个 子服务 ,一个路由就是一个小的服务(server/app)模块,处理一个接口
  2. 配置和使用
代码语言:txt
复制
* 创建模块文件:`/router/xx.js`
    
代码语言:txt
复制
              // 1.创建路由
代码语言:txt
复制
      let router = express.Router(); 
代码语言:txt
复制
      // 2.路由处理响应
代码语言:txt
复制
      router.响应API(地址, 处理函数);
代码语言:txt
复制
      // 3.导出路由
代码语言:txt
复制
      module.exports = router;
代码语言:txt
复制
* 主服务:`/app.js`
    
代码语言:txt
复制
              //安装路由
代码语言:txt
复制
      app.use('地址',router); 
代码语言:txt
复制
* 子路由/子服务/子模块:`/router/xx.js`
    
代码语言:txt
复制
              //子路由里安装路由 嵌套
代码语言:txt
复制
      router.use('地址',子router) 
代码语言:txt
复制
      //截获当前路由下的部分公共业务
代码语言:txt
复制
      router.all('*',当前router路由下的验证工作) //需要next 延续
代码语言:txt
复制
* 主路由的地址对应子路由的根 
  * 如:app.js: `/api/user` ~~ user.js: `/`
  * 如:app.js: `/api/user/add` ~~ user.js: `/add`

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
作者已关闭评论
0 条评论
热度
最新
推荐阅读
目录
  • 二、模块化开发
  • 三、express
  • 四、身份验证
    • (一)session
      • 如何保存信息给浏览器
      • cookie-session
    • (二)token
      • token的实现
    • (三)两者区别
    • 五、文件上传
      • (一)path模块
        • (二)multer中间件
        • 六、后端渲染
          • (一)jade
            • (二)ejs
            • 七、路由
            相关产品与服务
            对象存储
            对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档