express深入浅出

本文转自我的博客阅读原文
在我看来,express最亮眼的便是它的中间件。通过各种中间件,我们对服务中最重要的两个参数reqres进行加工,加工过后的reqres就有我们经常需要用到的数据以及更加好用的方法。

一览

  const express = require('express')
  const cookieParser = require('cookie-parser')
  const cookieSession = require('cookie-session')
  const bodyParser = require('body-parser')
  const multer = require('multer')
  const consolidate = require('consolidate')

  var server = express()
  server.listen(4001)

  // 1. 解析cookie
  server.use(cookieParser('nsdojgf45642norjes'))
  // 2. 使用session
  server.use(cookieSession({
    name: 'xuan_sess',
    keys: ['shd','dsr156er','nherisg','bdsrgfij'],
    maxAge: 1000*3600*20
  }))
  // 3. post数据
  server.use(bodyParser.urlencoded({extended: false}))
  server.use(multer({dest: './www/upload'}).any())
  // 4. 模板引擎
  server.set('view engine', 'html') // 要输出什么
  server.set('views', './views') // 指定模板目录
  server.engine('html', consolidate.ejs) // 指定引擎
  // 6. 接口处理
  server.get('/index', (req, res, next) => {
    res.render('1.ejs', {name: 'yesixuan'})
  })
  // 5. 静态数据
  server.use(express.static('./www'))

解析数据

解析get数据

express原生解析出get参数,并将其挂在req的query属性上。

  // ...
  server.get('/user', (req, res) => {
  // req.query,直接可以拿到查询参数
    console.log(req.query)
  })

解析post数据

解析post数据需要借助body-parser提供的中间件。它能帮助我们解析出post数据,并将其挂在req的body属性上。

  const bodyParser = require('body-parser')
  // ...
  server.use(bodyParser.urlencoded({extended: false})) // 取消扩展模式,免得它老是发出警告
  // ...
  console.log(req.body) // post数据

解析上传的二进制数据

解析上传的文件需要借助multer模块。它解析出来的数据挂在req.files上。

  const fs = require('fs')
  const pathLib = require('path')
  const multer = require('multer')
  // ...
  server.use(multer({dest: './www/upload'}).any()) // 指定文件上传的路径,不让buffer数据大量占用内存
  // ...
  /* 使用pathLib.parse('路径带文件名')可以解析更多信息,也可以拿到文件后缀名 */
  var newName = req.files[0].path + pathLib.extname(req.files[0].originalname)
  // 文件重命名,这里只是改了后缀名
  fs.rename(req.files[0].path, newName, err => {
    if(err)
      res.send('上传失败!')
    else
      res.send('ok!')
  })
  // ...
  console.log(req.files) // 对象数组,每个元素包含该文件的各种信息

cookie && session

cookie

cookie是在浏览器保存一些数据,每次请求都会带过来。只能存4k的数据。
使用cookie时要注意两点:① 空间小,精打细算;② 使用时要校验cookie是否被篡改。

  const cookieParser = require('cookie-parser')
  // ... 使用中间件,这里可以添加密钥作为中间件的参数
  server.use(cookieParser())
  // ... 写入cookie
  /* 指定只有在‘/aaa’下才有cookie,保质期为一个月,是否需要签名 */
  res.cookie(res.cookie('user', 'xuan', {path: '/aaa', maxAge: 30*24*3600*1000, signed: true}))
  // ... 读取cookies
  /* 读取,子级目录可以读根级。即树枝可以去寻根。例如/aaa/bbb可以读/aaa下的cookie */
  console.log(req.cookies)
  // ... 删除cookie
  res.clearCookie('user')

给cookie签个名。(签名虽然不能加密数据,但是可以保证数据一旦被篡改,我能够知道)

  // ...
  server.use(cookieParser('shdgopedfgh')) // 整个密钥
  res.cookie('user', 'xuan', {signed: true})
  console.log(req.cookies) // 没有签过名的cookie
  console.log(req.signedCookies) // 签过名的cookie

session

cookie没太多必要加密,真正机密的东西往session中放就好了。一定要用的话,cookie-encrypter。下面上session。

  const cookieSession = require('cookie-session')
  // ...
  // 这个要在cookieParser之下
  server.use(cookieSession({
    keys: ['aaa', 'bbb', 'ccc'], // 这个数组越长,越是安全
    name: 'sess', // 如果没这个参数,默认就是在cookie中的键名就是session
    maxAge: 1000*3600*2 // 两小时未操作,自动注销
  }))
  // ... 使用session
  server.use('/', (req, res) => {
    if(req.session['count'] == null) {
      req.session['count'] = 1
    }else {
      req.session['count']++
    }
    console.log(req.session['count'])
    res.send('ok')
  })
  // ... 删除session
  delete req.session // session是存储在服务器上的数据,所以我们可以使用JS原生的方法来删除session

后台模版

虽然后台模版渲染是与现代的开发方式背道而驰的,现在大家比较推崇的是后台提供数据,前端获取数据,渲染模版。
但是我在使用后台模版的时候,竟然找到了像撸react时相似的感觉。估计很多前端渲染模版的灵感也是来自后台模版吧。

模版渲染

  // consolidate帮我们整合了各种后台模版,甚至包括react
  const consolidate = require('consolidate')
  server.set('view engine', 'html') // 要输出什么
  server.set('views', './templates') // 指定模板目录
  server.engine('html', consolidate.ejs) // 指定引擎
  // ... {}里面传入模版中需要的参数
  res.render('index.ejs', {})

jade语法

  • 属性,使用小括号:img(src="./xx.jpg",alt="xxx")
  • 内容,空格往标签后面写:a 链接
  • style属性的对象写法:div(style={width:'200px',...})
  • class的数组写法:div(class=['aa',...])
  • 写class与id可以使用类似emmet写法
  • 标签后面加上&attributes,可以用对象方式写多个属性
  • 在内容前加‘|’,表示原样输出内容(script标签里的多行代码)
  • 在标签后加‘.’,表示里面的内容原样输出
  • include可以引入一个外部文件,include a.js(引入的内容还是嵌在页面中的)
  • 使用变量:#{变量},变量定义在renderFile(,{},)方法的‘{}’中(还可以写表达式)
  • 可以写两个class属性,jade自会处理好
  • 以‘-’开头的,解析为js。前面一行加了‘-’,下面与它平级或下级的都不用加‘-’
  • span #{name}与span=name,两者等价
  • 不让变量里面的尖括号被转义,在‘=’前面加‘!’
  • 原来的switch-case变成case-when结构。

ejs语法

  • 变量:<%= name %>
  • js语法:<% 脚本 %>
  • 引入外部文件的内容:<% include 路径 %>
  • include不是原生js的语法,所以使用include时,要单独起一行用“<% %>”包裹起来

express与数据库

连接mysql

  const mysql = require('mysql')
  // 使用连接池而不是创建连接,以提高性能(会创建多个链接,以保持跟数据库的持久通话)
  const db = mysql.createPool({
    host: 'localhost',
    user: 'root',
    password: '123456',
    database: 'blog'
    // ... 默认是3306端口的话,就不用在此处配置
  })
  // ... 增删改查(查询语句中使用反引号是极好的)
  db.query('select ID,title,summery from article_table', (err, data) => {
    if(err) {
      // 这里的链式操作也是推荐写法
      res.status(500).send('database err!').end()
    }else {
      // 将文章数据挂到res上,传递到下一层去。
      res.articles = data
      next()
    }
  })

连接mongodb

  const MongoClient = require('mongodb').MongoClient
  const databaseUrl = 'mongodb://localhost:27017/xuan'
  // ...
  MongoClient.connect(databaseUrl, (err, db) => {
    if(err) {
      res.status(500).send('database err!').end()
      return
    }
    res.send('数据库连接成功!')
    db.collection('teacher').insert({'name':'Mary'}, (err, result) => {
      if(err) {
        res.status(500).send('插入数据失败!').end()
        return
      }
      res.status(200).send('数据插入成功!').end()
      db.close()
    })
  })
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,839评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,543评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,116评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,371评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,384评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,111评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,416评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,053评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,558评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,007评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,117评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,756评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,324评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,315评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,539评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,578评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,877评论 2 345

推荐阅读更多精彩内容