node姿势点梳理

特点

  1. 事件驱动
  2. 非阻塞的IO (input output) 异步(高并发)

npm node包管理器

  1. npm init 初始化 生成package.json(项目配置文件)
  2. npm install 包名[@版本号] 安装包 -g 全局安装 --save-S安装到生产环境的依赖(记录在package.json里"dependencies") --save-dev-D 安装到开发环境的依赖(记录在package.json里"devDependencies")
  3. npm install 简写 npm i 项目移交时不需要拷贝node-modules文件夹,拿到项目文件,执行它,会下载package.json文件里记录所有的项目依赖

nrm

  • 使用nrm来切换npm下载地址(切换镜像源)。

npm虽然好用,但有它的下载地址是在国外,也就是说,每次使用 npm 下载的时候,都是去国外的服务器上进行下载,那么就会有很多不稳定的因素(慢,丢包等等),我们就可以nrm进行切换镜像的来源。

安装: npm install nrm -g

检测是否安装成功: nrm --version 查看版本号

查看可用的镜像列表:nrm ls

​查看 nrm 镜像源地址网速:nrm test

切换镜像源地址 nrm use 源名称 ,比如 nrm use taobao

包管理器

npm i yarn -g安装使用
yarn init 初始化
yarn add 包名 安装依赖,默认生产环境,相当于yarn add 包名 -S
yarn add 包名 --dev 安装开发环境依赖
yarn global add 包名 安装全局依赖
yarn remove 包名 移除依赖
yarn add 安装项目所有依赖

模块化

  • 模块分类
    系统模块、第三方模块、自定义模块
  • 模块导入
// 系统模块和下载到node_modules里的依赖引入不需要路径名
var xxx = require('modulexxx')
// 自定义模块引入必须加路径,即使在同一文件夹下也要加'./'
var a = require('./a')
  • 模块导出
    暴露一个接口
module.exports = {
  obj: {a:1},
  num: 1,
  str: '123',
  fn: function(){console.log('你好')}
}

暴露多个接口

exports.obj = {a:123}
exports.num = 3
exports.fn = function(){console.log('123...')}

// 导入接受到的是一个对象

注意当一个文件里面同时写了module.exports=exports.xxx=,导出的是module.exports=导出的对象啊

系统模块fs

const fs = require('fs');
// 目录
// 读取
// fs.readdir('./dir',(err,data)=>{
//   if (err){
//     console.log('出错了...')
//     return
//   }
//   // 返回的是一个数组,数组里面是文件夹下的所有文件
//   console.log(data)
// })

// try {
//   var data = fs.readdirSync('./dir2')
//   console.log(data)
// } catch (error) {
//   console.log(error)
// }

// 创建
// fs.mkdir('./dir2',(err)=>{
//   if(err){
//     // 已经存在这文件夹会报错
//     console.log(err)
//   }
// })

// 重命名
// fs.rename('./dir','./dir1',(err)=>{if(err) console.log(err)})

// 删除 只能删除空文件夹
// fs.rmdir('./dir1',(err)=>{
//   if(err) console.log(err)
// })

// 文件 
// 读取(注意输出的是二进制的数据流)
// fs.readFile('./dir1/a.txt',{encoding:'utf-8'},(err,data)=>{
//   if(err) {console.log(err); return}
//   // console.log(data.toString())
//   console.log(data)
// })

// 写入或创建
// var s = '我是写入的数据'
// fs.writeFile('./dir1/a.txt',s,(err)=>{if(err){ console.log(err); return}})

// 追加数据
// var s1 = '\n我是新追加的数据'
// fs.appendFile('./dir1/a.txt',s1,(err)=>{
//   if(err){
//     console.log(err)
//     return
//   }
// })

// 删除文件
// fs.unlink('./dir1/b.css',(err)=>{
//   if(err){
//     console.log(err)
//     return
//   }
// })

全局变量

// 文件所在目录的绝对路径
console.log(__dirname)
// 当前文件的绝对路径
console.log(__filename)
// node运行的文件目录的绝对路径
console.log(process.cwd())

系统模块path

const path = require('path')
// console.log(path)

// console.log(path.extname('./dir/a.txt'))

// 只是单纯的进行拼接
// console.log(path.join('/a','/b','c'))
// console.log(path.join('a','b','c'))
// console.log(path.join(__dirname,'a','b/c'))

// 会从右向左找根盘向右拼接,没根目录,用__dirname的根目录(e:)
// console.log(path.resolve('/a','b','c'))// e:\a\b\c
// console.log(path.resolve('a','/b','c')) //e:\b\c

系统模块url

const url = require("url");
var s = "http://www.conner.com/a/index?query=xx#first"
// 将字符串url地址转换成对象
console.log(url.parse(s))
var urlObj = {
  protocol: 'http:',
  slashes: true,
  auth: null,
  host: 'www.conner.com',
  port: null,
  hostname: 'www.conner.com',
  hash: '#first',
  search: '?query=xx',
  query: 'query=xx',
  pathname: '/a/index',
  path: '/a/index?query=xx',
  href: 'http://www.conner.com/a/index?query=xx#first'
}
// 将对象格式化成url地址字符串
console.log(url.format(urlObj))

系统模块https

// 导入,注意http和https是两个模块
const https = require('https')
const cheerio = require('cheerio')
var imgArr = []

// 可以搞代理,简易爬虫
https.get('https://www.tupianzj.com/meinv/mm/',(res)=>{
  res.setEncoding('utf-8')
  var rawData=""
  // 绑定两个事件
  // 获取数据分片处理数据
  res.on('data',(chunk)=>{
    rawData += chunk
  })
  // 处理数据结束后在回调函数使用处理过的数据
  res.on('end',()=>{
    // cheerio是jquery核心功能的一个快速灵活而又简洁的实现,主要是为了用在服务器端需要对DOM进行操作的地方
    // rawData是爬取的网页富文本
    var $ = cheerio.load(rawData)
    $('img').each((i,el)=>{
      imgArr.push($(el).attr('src'))
    })
    console.log(imgArr)
  })
}).on('error',(e)=>{
  console.log(e.message)
})

express脚手架的使用(其他脚手架 koa egg.js)

初始化npm package.json

npm init -y

安装

npm i express -S

使用

const express = require('express')
// 创建一个服务
const app = express()
// 监听一个端口
app.listen(9527,()=>{console.log("server is running")})

开启服务(执行js文件)

node 文件名.js
app.get('/a',(req,res)=>{
  res.send('你好express')
})

app.post('/b',(req,res)=>{
  res.send('你好express/b')
})

访问
浏览器地址栏输入localhost:9527

每次重新配置服务,要关掉开的服务再重启,比较麻烦,使用nodemon就可以了
nodemon用来监视node.js应用程序中的任何更改并自动重启服务,非常适合用在开发环境中。
全局安装nodemon

npm i nodemon -g

再开启服务的时候使用nodemon开启

nodemon 文件名.js

中间件(middleware)

中间件其实就是函数,使用时会可以对请求和响应做一些处理

自制中间件

// 说白了,中间件就是函数
var middleWare1 = (req,res,next) => {
  // 请求时(写在next上面的)的拦截处理
  console.log('我是中间件1')
  // 必须要放行,不然请求会一直得不到响应
  next()
  // 响应时(写在next下面的)的拦截处理
  console.log(111)
}
var middleWare2 = (req,res,next) => {
  console.log('我是中间件2')
  next()
  console.log(222)
}

使用
给创建的服务使用
语法: app.use([path,]middleware1)

  1. 可以链式使用,或一次使用多个
  2. 不写路径参数是默认全局中间件,等价于路径’/’,写路径参数是局部的,只对对应接口做处理
app.use(middleWare1).use(middleWare2)
app.use('/a',middleWare1,middleWare2)
  1. 起到类似于大坝的作用 请求的时候按正向顺序拦截,响应的时候按逆向顺序拦截
app.use('/a',middleWare1,middleWare2)
app.get('/a',(req,res)=>{
  res.send('apiaaa')
})

发起请求 =>localhost:9527/a
输出=>我是中间件1 \n 我是中间件2 \n 222 \n 111

请求的参数获取

  • 咋发请求
    发送get请求直接地址栏输入就行了
    发送post请求,可以使用表单发送(method=“post”);ajax请求;使用postman
  • get请求参数的获取
// get请求直接req.query就可以拿到
app.get('/a',(req,res)=>{
  console.log(req.query)
  res.send('hello a')
})
  • post请求参数的获取(要下载body-parser中间件)
    下载安装
npm i body-parser -S

使用中间件后可获取post的请求参数

导入中间件

const bodyParser = require('body-parser')

使用中间件

// 配置好,可以解析x-www-form-urlencoded的参数
app.use(bodyParser.urlencoded({extended:false}))
// 配置好,可以解析json格式的参数
app.use(bodyParser.json())
app.post('/b',(req,res)=>{
  // 如果直接使用是undefined没有的,必须使用中间件处理一下
  console.log(req.body)
  res.send('hello b')
})

路由中间件

就是express的函数,只要下载,导入了express就可以使用
使用

// 注意:express.Router()是大写的R
var router = express.Router()
// 一定要记得使用一下,它是个中间件
app.use(router)

router其实就相当于一个服务,同样可以设置拦截,使用插件

var bodyParser = require('body-parser')

router.use(bodyParser.urlencoded({extended:false}))
router.use(bodyParser.json())

router.get('/a',(req,res)=>{
  console.log(req.query)
  res.send('api aaaa')
})

router.post('/b',(req,res)=>{
  console.log(req.body)
  res.send('api bbbb')
})

一个服务器会用到很多接口,都写在index.js文件里不好维护,可以单独提出放在一个文件夹routers里,不同api放不同文件,模块化管理
项目文件夹/routers/home.js

const express = require('express')
const router = express.Router()

router.get('/home',(req,res)=>{
  // console.log(req.query)
  res.render('home')
})

module.exports = router

服务文件中使用

const express = require('express')
const homeRouter = require('./routers/home')
const newsRouter = require('./routers/news')
const bodyParser = require('body-parser')
var app = express()
app.use(bodyParser.urlencoded({extended:false}))
app.use(bodyParser.json())
// 注意别忘了使用它们***
app.use(homeRouter,newsRouter)

app.listen(9527,()=>{
  console.log('server is running...')
})

静态资源托管

通常网页静态资源放在项目文件的public文件夹下,静态文件images,html,js,css,lib等

const express = require('express')
const app = express()
app.use(express.static('./public'))
app.listen(9527,()=>{
  console.log("serve is running...")
})

配置好后就可以通过浏览访问服务器上的静态资源了(如访问 项目文件夹/public/images/a.jpg)
地址/ => public/
浏览器地址栏输入http://localhost:9527/images/a.jpg

模板引擎

后端一手模板一手数据拼好响应给浏览器

模板引擎 主要功能在于 渲染页面(取代了传统了 拼接字符串)
常见的nodejs 模板引擎有哪些
ejs 温和的 非破坏式 (内部写法跟html是一样的只是赋予了html 一些渲染的功能,如循环,条件判断,引入公共模板…)
pug jade 侵入式 (破坏式) 破坏了html 原有的写法

模板引擎 渲染页面的(html写循环,判断…)

ejs模板引擎的是使用

下载依赖

npm i ejs -S

通常将模板文件放在 项目文件夹/views/下
head.ejs文件


<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Documenttitle>

head>

home.exjs文件


<%- include('head') -%>
<body>
  <h1>我是首页h1>
  
  <p><%= msg %>p>
  
  <% for(i in arr) {%>
    <li><%= arr[i] %>li>
  <%}%>
  <% if (!sign) { %>
    <p>这个人很懒,啥都没有留下p>
  <% } else { %>
    <p><%= sign %>p>
  <% } %>
  
  <%- richStr %>
  
body>
html>

常用语法
<%js语句%> 可以解析js语句,条件,循环;是按照每行一一对应的,每行js语句都要包一下
<%=变量%> 可以解析变量
<%-include('xxx')-%> 用来导入公共的模板文件
<%-富文本字符串%> 可以解析标签(通常为了防止注入攻击,模板都不会去主动解析html标签)

服务文件中配置
不需要引入依赖,只需要配置使用的模板引擎名称,和文件路径就行了

app.set("views","./views")  // 告诉服务模板文件放在哪个文件夹下
app.set("view engine","ejs")// 告诉服务是哪种模板语法

文件中使用

const express = require('express')
const router = express.Router()
router.use('/home',(req,res)=>{
  // 因为已经告诉服务(设置了)文件目录和模板类型

  // 响应渲染方法,返回一个解析好的html页面
  res.render('home',{
    msg: '我是变量',
    arr: ["xx","oo","nn","mm","jj","ff"],
    richStr: '

我是富文本内容

', sign: '除了我,还有谁' }) }) module.exports = router

multer中间件

用来处理上传的文件,并对文件进行一些操作(如设置扩展名)

下载安装

npm i multer -S

文件上传

  1. 直接通过form表单提交

pro/views/home.ejs

...
<body>
  <form action="/upload" method="post" enctype="multipart/form-data">
    
    <input type="file" name="img" id="">
    <input type="submit" value="提交文件">
  form>
body>
  1. 通过ajax(jquery)上传
<body>
  <input type="file" id="file">
  <img src="" alt="">

  <button>提交button>
  
  <script>
    var formData = new FormData()
    // 定义个容器
    // 二进制文件数据流格式转换
    $('#file').change(function(){
      // 把它扔给img这个变量,single里面的接受的就是它,跟input:file name差不多
      formData.append("img",this.files[0])
      var fd = new FileReader();
      // base64
      fd.readAsDataURL(this.files[0]);
      // 图片预览功能实现
      fd.onload = function () {
        console.log(this.result)
        $('img').attr("src",this.result)
      }
    })
    // 报错Illegal invocation
    // processData
    // 类型:Boolean

    // 默认值: true。默认情况下,通过data选项传递进来的数据,如果是一个对象(技术上讲只要不是字符串),
    // 都会处理转化成一个查询字符串,以配合默认内容类型 "application/x-www-form-urlencoded"。
    // 如果要发送 DOM 树信息或其它不希望转换的信息,请设置为 false。

    $('button').click(function(){
      $.ajax({
        url:'/upload',
        type:'POST',
        dataType:'json',
        data:formData,
        processData:false,//把默认数据格式关了
        contentType:false,
        success: function(res){
          console.log(res)
        }
      })
    })
  script>
body>
  1. 配置一下接受文件存放路径,添加文件扩展名
    pro/utils/upload.js
const multer = require('multer')
// 最后路由文件都会挂到index.js上,所以路径·
// var upload = multer({dest: './public/uploads/'})
// single里的参数是上传文件的表单元素的name属性值

var storage = multer.diskStorage({
  destination: function (req, file, cb) {
    // 最后路由文件都会挂到index.js上,所以路径·
    cb(null, './public/uploads')
  },
  filename: function (req, file, cb) {
    console.log(file)
    var extName = file.mimetype.split('/').reverse()[0]
    cb(null, file.fieldname + '-' + Date.now()+"."+extName)
  }
})
 
var upload = multer({ storage: storage })

module.exports = upload
  1. 文件上传的页面路由
const express = require('express')
const router = express.Router()
// ***注意路径
const upload = require('../utils/upload')
// single里面的是表单元素的name值
router.post('/upload', upload.single('img'),(req,res)=>{
  res.send('hello')
})

module.exports = router
  1. 服务文件中导入路由文件
const express = require('express')
const bodyParser = require('body-parser')
const app = express()
const homeRouter = require('./routers/home')
const uploadRouter = require('./routers/upload')
app.use(express.static("./public"))
app.use(homeRouter,uploadRouter,bodyParser.urlencoded({extended:false}),bodyParser.json())
app.set('views','./views')
app.set('view engine','ejs')
app.listen(9527,()=>{
  console.log("serve is running...")
})

mongodb使用

安装开服务

  1. 下载安装mongodb
  2. 将mongodb/bin配置到全局环境变量
  3. 在安装文件夹下建data文件夹,在data文件夹下建db文件夹
  4. 开启mongodb服务
mongod --dbpath db文件夹绝对路径

  1. 客户端链接(再开个cmd)
mongo

原生sql语句

show dbs 查看有哪些数据库
use 数据库名 切换使用的数据库
show collections 查看当前数据库下有那些集合,所有的操作都需要切换到目标数据库才能执行
db.createCollection("person") 创建一个集合
db.集合名.drop() 删除集合

集合等价于mysql里的表单,文档等价于mysql里的记录
文档的数据结构和JSON基本一样。
所有存储在集合中的数据都是BSON格式。
BSON是一种类json的一种二进制形式的存储格式,简称Binary JSON

增删改查

  1. 查看文档(查)

find方法会检索集合中所有文档结果

db.集合名.find()

{ "_id" : ObjectId("5eeb59318fbe4d2a7d24ef0e"), "name" : "tom", "age" : 18, "gender" : 0 }
{ "_id" : ObjectId("5eeb59458fbe4d2a7d24ef0f"), "name" : "lucy", "age" : 19, "gender" : 1 }
{ "_id" : ObjectId("5eeb59528fbe4d2a7d24ef10"), "name" : "nacy", "age" : 17, "gender" : 1 }
{ "_id" : ObjectId("5eeb59638fbe4d2a7d24ef11"), "name" : "jack", "age" : 18, "gender" : 0 }

返回的结果不美观,可以格式化一下
db.student.find().pretty()

{
        "_id" : ObjectId("5eeb59318fbe4d2a7d24ef0e"),
        "name" : "tom",
        "age" : 18,
        "gender" : 0
}
{
        "_id" : ObjectId("5eeb59458fbe4d2a7d24ef0f"),
        "name" : "lucy",
        "age" : 19,
        "gender" : 1
}
{
        "_id" : ObjectId("5eeb59528fbe4d2a7d24ef10"),
        "name" : "nacy",
        "age" : 17,
        "gender" : 1
}
{
        "_id" : ObjectId("5eeb59638fbe4d2a7d24ef11"),
        "name" : "jack",
        "age" : 18,
        "gender" : 0
}

固值查找
db.student.find({name:"lucy"}) 等价于where name = 'lucy'

范值查找

  • 相等 {:} db.student.find({name:"lucy"}).pretty() 等价于 where name = 'lucy'
  • 小于 {:{$lt:}} db.student.find({age:{$lt:18}}).pretty() 等价于 where age < 18
  • 小于等于 {:{$lte:}} db.student.find({age:{$lte:18}}).pretty() 等价于 where age <= 18
  • 大于 {:{$gt:}} db.student.find({age:{$gt:18}}).pretty() 等价于 where age > 18
  • 大于等于 {:{$gte:}} db.student.find({age:{$gte:18}}).pretty() 等价于 where age >= 18
  • 不等于 {:{$ne:}} db.student.find({"age":{$ne:18}}).pretty() 等价于 where age != 50

AND和OR查找
and 寻找年龄>=18且性别为女的

db.student.find({
  $and:[{
    age: {
      $gte: 18
    }
  },{
    gender: 1
  }]
})

db.student.find({KaTeX parse error: Expected '}', got 'EOF' at end of input: and:[{age: {gte: 18}},{gender: 1}]})

or 查询年龄为17或者为男性

db.student.find({
  $or:[{
    age: 17
  },{
    gender: 0
  }]
})

db.student.find({$or:[{age: 17},{gender: 0}]})

结合查询
相当于语句where name = "lucy" OR ( gender = 1 AND age > 18)

db.student.find({
  $or:[{
    name: "lucy"
  },{
    $and:[{
      gender: 1
    },{
      age: {
        $gt: 18
      }
    }]
  }]
})

db.student.find({KaTeX parse error: Expected '}', got 'EOF' at end of input: …name: "lucy"},{and:[{gender: 1},{age: {$gt: 18}}]}]})

  1. 插入文档(增)
    要将数据插入到mongodb集合中,需要使用mongodb的insert()save()方法。
db.集合名.insert(document)

比如我们可以插入以下数据

db.wscats.insert({
_id: 100,
title: 'MongoDB Tutorials', 
description: 'node_tutorials',
by: 'Oaoafly',
url: 'https://github.com/Wscats/node-tutorial',
tags: ['wscat','MongoDB', 'database', 'NoSQL','node'],
num: 100,
})

可以插入多个,多个是以数组的形式插入的

db.student.insert([{
  name:'alius',
  age: 36,
  gender: 1
},{
  name:'plus',
  age: 28,
  gender: 0
}])

在插入的文档中,如果不指定_id参数,那么mongodb会为此文档分配一个唯一的ObjectId
要插入文档,也可以使用db.post.save(document)。如果不在文档中指定_id,那么save()方法将与insert()方法一样自动分配ID的值。如果指定_id,则将以save()方法的形式替换包含**_id**的文档的全部数据。

save指定的_id之前没有存在就是插入,有就是替换,而insert指定_id存在就插入不了报错

db.student.save({_id: 111,name:'yells',age: 23,gender: 1})
  1. 更新文档(改)

update(条件,{$set:{要修改的字段}})
寻找所有age>19的值,并且更新值name为return和age为18

db.student.update({'age': {$gt: 19}}, {$set: {'name': 'return','age': 18}}, { multi: true})

save
根据_id来查找,覆盖修改数据,id为必传key值

  1. 删除文档(删)
    删除主键_id为3的文档,默认是删除多条
db.student.remove({
'_id':111
})

建议在执行remove()函数前先执行find()命令来判断执行的条件是否正确

如果你只想删除第一条找到的记录可以设置justOne为1,如下所示

db.student.remove({...},1)

全部删除

db.student.remove({})

Limit和Skip方法

limit一次取几条数据
skip跳过多少条读取

sort()排序
1升序,-1降序

利用mongoose链接mongodb

中文文档 http://www.mongoosejs.net/docs/

你可能感兴趣的:(node姿势点梳理)