nodejs

 最近学习了一些nodejs中的知识,整理一下,也只是一部分,后面学到用到慢慢更新

命令行窗口(小黑屏)、cmd窗口、终端

 window + R  -->  cmd  --> 回车

-- 常用的指令:

        dir 列出当前目录下的所有文件

        cd  目录名  进入到指定的目录

        md 目录名  创建一个文件夹

        rd   目录名  删除一个文件夹

        cls  清空终端

 -- 目录

        . 表示当前目录

        ..表示上一级目录

 node.js三大模块:内置模块,自定义模块,第三方模块

path模块

path.join(__dirname,path1,path2,...)

(路径拼接) 

path. basename(path) 

(从一个文件路径中获取到文件的名称)

path. extname(path) 

 (获取路径中的扩展名)

__dirname 

  (总是返回被执行的 js 所在文件夹的绝对路径)

__filename 

(总是返回被执行的 js 的绝对路径) 

process.cwd() 

  (总是返回运行 node 命令时所在的文件夹的绝对路径) 

const path = require('path')

let testPath = 'a/b/c/file.txt'

/*
 * basename
 */
console.log(path.basename(testPath)) //  file.txt
console.log(path.basename(testPath,'.txt')) //  file

/*
 * extname
 */
console.log(path.extname(testPath)) //  .txt

/*
 * __dirname
 */
console.log(__dirname)   //D:\node-test

/*
 * __filename
 */
console.log(__filename)   //D:\node-test\path.js


/*
 * join()
 */
console.log(path.join(__dirname,'a/b/c'))  //D:\node-test\a\b\c

fs模块(File System)

fs.readFile(path,'utf8',callback);

fs.readFileSync(path,'utf8')

(异步读取文件)

  (同步读取文件,无callback,有返回值。返回值即读取的内容)

fs.writeFile(path,data,'utf8',callback) 

fs.writeFileSync(path,data,'utf8')

(异步写入文件,第三个参数如果不写,默认为utf8) 

(同步写入文件,无callback) 

下面是个小练习(异步演示)。我会把txt1.txt中的内容(小红=90 小明=80 小兰=20 小红=70 小敏=50),写到text/text1.txt中

const fs = require('fs')
const path = require('path')

var fromPath = path.join(__dirname,'txt1.txt')
var toPath = path.join(__dirname,'text/text1.txt')

fs.readFile(fromPath,'utf8',(err,data) => {
  if(err) {
    console.log(err,'读文件错误-->>')
  }else {
    console.log(data,'读文件成功-->>')
    handlerDataWrite(data)
  }
})
function handlerDataWrite(dataStr) {
  let targetDataStr = dataStr.split(' ').map(item => item.replace('=',':')).join('\r\n')

  fs.writeFile(toPath,targetDataStr,(err,data) => {
    if(err) {
      console.log(err,'写入失败')
    }else {
      console.log('写入成功')
    }
  })
}

 写完之后就是下面这个形式:

fs.readdir(path,callback) 

fs.readdirSync(path) 

(异步读取目录,读到一个包含该路径下的文件和文件夹的数组) 

(同步读取目录,无callback,返回一个包含该路径下的文件和文件夹的数组)

fs.readdir(path.join(__dirname,'pages'),(err,files) => {
  if(err) {
    console.log(err,'err--->>')
  }else {
    console.log(files,'files--->>>') // [ 'index.html', 'login.html', 'page' ] files--->>>
  }
})

let dirs = fs.readdirSync(path.join(__dirname,'pages'))
console.log(dirs,'读取的目录->')  //  [ 'index.html', 'login.html', 'page' ] 读取的目录->

fs.rmdir(path,{recursive:true,force:true},callback) 

fs.rmdirSync(path,{recursive:true,force:true}) 

(异步删除目录,如果不写第二个参数,则只能删除空文件夹,有回调函数)

(同步删除目录,如果不写第二个参数,则只能删除空文件夹,无回调函数)

 fs.mkdir(path,[mode],callback) 

fs.mkdirSync(path,[mode]) 

(异步创建目录,mode为目录权限(读写权限),默认为0777)

(同步创建目录,创建目录,mode为目录权限(读写权限),默认为0777)

fs.unlink(path,callback) 

fs.unlinkSync(path) 

  (异步删除文件,有回调函数)

  (同步删除文件,无回调函数)

fs.stat(path,callback) 

fs.statSync(path) 

stat方法的参数是一个文件或目录,它产生一个对象,该对象包含了该文件或目录的具体信息。我们往往通过该方法,判断正在处理的到底是一个文件,还是一个目录

isDirectory() 

(返回一个布尔值,判断是否为文件夹)

isFile() 

(返回一个布尔值,判断是否为文件)  

下面是个例子:我会把根路径下modules下的dist文件夹替换为根路径的dist文件夹 

const fs = require('fs')
const path = require('path')


let modulesPath = path.join(__dirname,'modules/dist')
let distPath = path.join(__dirname,'dist')

fs.rmdirSync(modulesPath,{  //递归删除modules下的dist目录
  recursive:true,
  force:true
})

let dirs = [{
  absolutePath:distPath,
  realtivePath:''
}]

for(let dir of dirs) {
  fs.mkdirSync(path.join(modulesPath,dir.realtivePath))                                //在目标路径下创建目录
  let names = fs.readdirSync(dir.absolutePath)                                         //读取源目录            
  console.log(names)
  for(let name of names) {
    let stats = fs.statSync(path.join(dir.absolutePath,name))                          //读取源文件(文件夹)
    if(stats.isDirectory()) {                                                          //如果是文件夹,就push进去,然后会在目标路径下再次创建同样名称目录
      dirs.push({
        absolutePath:path.join(dir.absolutePath,name),
        realtivePath:path.join(dir.realtivePath,name)
      })
    }else if(stats.isFile()) {                                                         //如果是文件,就直接读取该文件,然后将读取的数据写入目标文件
      let readData = fs.readFileSync(path.join(dir.absolutePath,name))
      fs.writeFileSync(path.join(modulesPath,dir.realtivePath,name),readData)          //写入文件。注意:如果该路径没有此文件名称,则会创建该文件
    }
  }
}

os模块(操作系统模块)

os.cpus()

返回计算机中cpu相关信息 

os.totalmem() 

(返回计算机中的可用内存,返回的是B(字节);/1024=KB/1024=MB/1024=G 

os.EOL 

一个字符串常量,定义操作系统相关的行末标志:

  • \n 在 POSIX 系统上
  • \r\n 在 Windows系统上

os.arch() 

返回一个字符串, 表明Node.js 二进制编译 所用的 操作系统CPU架构 

现在可能的值有: arm, arm64ia32mipsmipselppcppc64s390s390xx32x64, 和 x86

os.homedir() 

以字符串的形式返回当前用户的home目录 

os.hostname() 

以字符串的形式返回操作系统的主机名 

os.networkInterfaces() 

 返回一个对象,包含只有被赋予网络地址的网络接口;

在返回对象的每个关键词都指明了一个网络接口;

返回的值是一个对象数组, 每个都描述了赋予的网络地址;

被赋予网络地址的对象包含的属性:

  • address(被赋予的 IPv4 或 IPv6 地址)
  • netmask (IPv4或Ipv6子网掩码)
  • family (IPv4 或 IPv6)
  • mac (网络接口的MAC地址)
  • internal (如果网络接口是loopback或相似的远程不能用的接口时,值为true,否则为false)
  • scopeid (IPv6 数字领域识别码 (只有当family 是 IPv6时可用))
  • cidr (返回当前域名及端口)

os.platform() 

返回一个字符串, 指定Node.js编译时的操作系统平台 ;

可能的值有:

  • aix
  • darwin
  • freebsd
  • linux
  • openbsd
  • sunos
  • win32

os.release() 

返回一个字符串, 指定操作系统的发行版 

os.tmpdir() 

返回一个字符串, 表明操作系统的 默认临时文件目录 

os.type() 

返回一个字符串,表明操作系统的名字.举个例子 'Linux'  在 Linux系统上,  'Darwin' 在 macOS 系统上 , 'Windows_NT'  在 Windows系统上

http模块

// http 模块
const http = require('http')
const fs = require('fs')
const path = require('path')

var server = http.createServer()

var loginPath = path.join(__dirname,'pages/login.html')

server.on('request',(req,res) => {
  let url = req.url,
  let method = req.mathod
  console.log(`请求的路径->${url},请求方式->${method}`)
  if(url == '/login') {
    // res.setHeader('content-type','text/plain;charset=utf-8')
    fs.readFile(loginPath,(err,data) => {
      if(err) {
        console.log(err,'读文件错误')
      }else {
        console.log('读文件成功')
        res.end(data)
      }
    })
  }else if(url == '/jxhtml') { //解析html标签
    res.setHeader('content-type','text/html;charset=utf-8')
    res.end('<h1>解析html标签</h1>')
  }
})


server.listen(3000,() => {
  console.log('服务器跑起来~~~~')
})

 CommonJS模块化规范

nodejs遵循了CommonJS模块化规范,CommonJS规定了模块的特性和各模块之间如何相互依赖 

CommonJS规定: 

① 每个模块内部,module变量代表当前模块

②  module变量是一个对象,它的exports属性(即module.exports)是对外的的接口

③ 加载每个模块,其实是加载该模块的module.exports属性。require()方法用于加载模块

Express 

 Express是基于Node.js平台,快速开发、开放、极简的Web开发框架

 Express作用和Node.js内置模块http类似,是专门用来创建Web服务器的

 本质就是一个npm上的第三方包,提供了快速创建Web服务器的便捷方法

  http内置模块用起来复杂,开发效率低,Express是基于内置的http模块进一步封装出来的,能够极大的提高开发效率

npm install express --save 

const express = require('express')

const app = express()

app.get('/getList', (req,res) => {
  // res.setHeader('Access-Control-Allow-Origin','*')  //允许跨域
  res.send({name:'哈哈哈',id:1,text:'上天了'})
})
app.post('/login',(req,res) => {
  // res.setHeader('Access-Control-Allow-Origin','*')  //允许跨域
  res.send('xxxxx')
})

app.listen(3000, () => {
  console.log("Server running at http://127.0.0.1")
})

Express路由 

为了方便对路由进行模块化管理,Express不建议将路由直接挂载到app上,而是推荐将路由抽离为单独的模块,创建步骤: 

① 创建路由模块对应的js文件

② 调用expross.Router()函数创建路由对象

③ 向路由对象上挂载具体的路由

④ 使用 module.exports 向外共享路由对象

⑤ 使用app.use()函数注册路由模块

 

中间件

(非错误中间件)

① 一定要在路由之前注册中间件 

② 客户端发送过来请求,可以连续调用多个中间件进行处理

③ 执行完中间件的业务代码后,不要忘记调用next()函数

④ 为了防止代码逻辑混乱,调用next()函数后不要再写额外的代码

⑤连续调用多个中间件时,多个中间件,共享 req 和 res 对象

 (错误中间件)

作用:专门用来捕获整个项目发生的异常错误,从而防止项目异常崩溃的问题

格式:错误级别中间件的function函数中,必须有四个形参,从前到后,分别是(err,req,res,next)

throw new Error("服务器内部出错") :抛出一个自定义的错误后,回去回调错误中间件,err.message就是上面("服务器内部出错")

注意:错误级别中间件,必须注册在所有路由之后

Express内置中间件

 express.static

快速托管静态资源的内置中间件,例如:HTML文件、图片、css样式等(无兼容性)

express.json() 

解析JSON格式请求体数据(有兼容性,仅在4.16.0+ 版本可用)

express.urlencoded() 

解析URL-encoded格式的请求体数据(有兼容性,仅在4.16.0+ 版本可用)

CORS跨域资源共享

 使用cors中间件解决跨域问题 

cors是Express的一个第三方中间件,通过安装和配置cors中间件,可以很方便的解决跨域问题 

使用步骤:

①  运行npm install cors 安装中间件

②  使用 const cors = require("cors") 导入中间件

③  在路由之前调用 app.use(cors()) 配置中间件 

注意事项:

① CORS主要在服务端配置,客户端浏览器无需做任何额外配置,即可请求

②  CORS在浏览器有兼容性。只有支持XMLHttpRequest Level2的浏览器,才能正常访问开启了cors的服务端接口(例如:IE10+、Chrome4+、FireFox3.5+)

const cors = require('cors')

// 配置cors中间件(一定是在路由之前)  解决跨域问题 客户端不需要做处理
app.use(cors())

Express中使用JWT

1.安装 JWT相关的包

 npm install jsonwebtoken express-jwt

其中:

jsonwebtoken 用于生成 JWT字符串

express-jwt  用于将 JWT 字符串解析还原成JSON对象

2.导入 JWT 相关的包

 使用 require 函数分别导入 JWT 相关的两个包

//  1. 导入用于生成 JWT 字符串的包
const jwt = require('jsonwebtoken')
//  2. 导入用于将客户端发过来的 JWY 字符串 解析还原还原成 JSON 对象的包
const expressJWT = require('express-jwt')

3.定义 secret 密钥 (本质就是一个字符串)

为了保证 JWT 字符串的安全性,防止 JWT 字符串在网络传输过程中被别人破解,我们需要定义一个用于加密和解密的 secret 密钥:

① 当生成 JWT 字符串的时候,需要使用secret密钥对用户信息进行加密,最终得到加密好的字符串

② 当把 JWT 字符串解析还原成 JSON 对象的时候,需要使用 secret 密钥进行加解密

// 定义一个 secret 密钥 本质:就是一个字符串
const secretKey = 'itheima No ^_^'

4. 在登录成功后生成JWT 字符串,响应给客户端:

// 登录接口
router.post('/login', (req, res) => {
  const userInfo = req.body  // 用户信息(包含用户名、密码等)
  // 登录失败的情况
  if(userInfo.username !== 'admin' || userInfo.password !== '123456') {  // 去数据库查询 有没有这个用户 或者 密码是否正确
    return res.send({
      status: 400,
      message: '登录失败!'
    })
  }
  /**
   * 登录成功的情况
   * 调用 jsonwebtoken 中的 sign() 方法生成 jwt 字符串 发送给客户端
   * 参数1: 用户的信息对象 (为了保证安全,不要把密码加密到token字符串中)
   * 参数2: 加密的密钥
   * 参数3: 配置对象,可以配置当前token的有效期
   */
  const tokenStr = jwt.sign({ username: userInfo.username }, secretKey, { expiresIn: '10h' })
  res.send({
    status: 200,
    message: '登录成功!',
    token: tokenStr
  })
})

5.将 jwt 字符串还原成 JSON 对象

客户端每次在访问那些有权限接口的时候,都需要主动通过请求头中的Authorization字段,将token字符串发送到服务器进行身份认证。

此时,服务器可以通过express-jwt这个中间件,自动将客户端发送过来的Token解析还原成JSON对象:

// 使用app.use()来注册中间件
// expressJWT({ secret: secretKey, algorithms: ['HS256'] }] 用来解析token的中间件,
//其中algorithms设置jwt的算法。一般HS256为配置algorithms的默认值

//.unless({ path: ['/login'] }) 用来指定哪些接口不需要访问权限

/** 
 *  注册解析 jwt 字符串还原成json对象的 中间件
 *  只要配置了这个中间件 就可以把解析出来的用户信息,挂载到req.user 属性上
 */
app.use(expressJWT({ secret: secretKey, algorithms: ['HS256'] }).unless({ path: ['/login'] }))

6. 使用 req.user 获取用户信息

除了login接口 其他的携带token接口的 都可以通过 req.user 访问到当前的用户 

7. 捕获解析 JWT失败后 产生的错误 

当使用express-jwt解析Token字符串时,如果客户端发送过来的Token 字符串 过期或者不合法,会产生一个解析失败的错误,影响项目的正常运行,我们可以通过Express的全局错误中间件来捕获这错误,并进行相关的处理,示例代码:

/**
 *  全局错误中间件
 *  必须写在所有接口之后
 *  捕获错误
 */
app.use((err, req, res, next) => {
  console.log('触发了全局错误中间件')
  //  token 解析失败导致的错误
  if(err.name == 'UnauthorizedError') {
    return res.send({
      status: 401,
      message: '无效的token'
    })
  }
  // 其他错误
  res.send({
    status: 500,
    message: err.message || '未知错误'
  })
})

补充:客户端发送请求 在请求头上携带token的时候  一般要在前面加上Bearer,然后空格隔开,后面是token

在项目中操作MySQL 

安装 mysql 

npm install mysql

导入mysql、建立Mysql 数据库的连接关系

// 导入mysql模块
const mysql = require('mysql')

// 建立 Mysql 数据库的连接关系
const db = mysql.createPool({   //或者createConnection
  host: '127.0.0.1',   //数据库的 IP 地址
  user: 'root',  // 登陆数据的账号
  password: 'admin',  // 登录数据库的密码
  database: 'my_db_01'  // 指定要操作哪个数据库
})

 测试 Mysql能否正常工作

/**
 * 测试 Mysql 能否正常工作
 */
db.query('select 1', (err, results) => {
  //  Mysql模块工作期间报错了
  if(err) return console.log(err.message)

  // 能够正常的执行Mysql 语句
  console.log(results)
})

 插入数据(增) 


/**
 *   插入数据(增)
 */

//  1.  要插入到 users 表中的数据对象
const user = { username: 'xxx', password: 'xxx' }
// 2.待执行的 SQL 语句 , 其中 ? 表示占位符
const sqlStr = 'INSET INTO users (username, password) VALUES (?, ?)'
// 使用数组的形式, 依次为 ? 占位符 指定具体的值
db.query(sqlStr, [user.username, user.password], (err, results) => {
  if(err) return console.log(err.message)  //失败
  if(results.affectedRows === 1) {
    console.log('插入数据成功')
  }
})


//  1.  要插入到 users 表中的数据对象(便捷方式)
const user = { username: 'xxx', password: 'xxx' }
// 2.待执行的 SQL 语句 , 其中 ? 表示占位符
const sqlStr = 'INSET INTO users SET ?'
// 使用数组的形式, 依次为 ? 占位符 指定具体的值
db.query(sqlStr, user, (err, results) => {
  if(err) return console.log(err.message)  //失败
  if(results.affectedRows === 1) {
    console.log('插入数据成功')
  }
})

 查询数据(查)

sql语句 select * from users order by id desc(按照id进行降序的排序 asc表示升序,默认是升序排序,多重排序用逗号隔开即可)

/**
 *  查询数据 (查)
 */

//  查询users表中所有数据  (* 代表所有  想查询某些个字段 将 * 替换为对应的key 即可)
db.query('SELECT * FROM users', (err, results) => {
  if(err) return console.log(err.message)
  //  查询成功
  console.log(results)
})

 更新数据(改)

// 要更新的数据对象
const user = { id: 7, username: 'xxx', password: 'xxx'}
//  要执行的SQL语句
const sqlStr = 'UPDATE users SET username=?, password=? WHERE id=?'
db.query(sqlStr, [user.username, user.password, user.id], (err, results) => {
  if(err) return console.log(err.message) //失败
  if(results.affectedRows === 1) {
    console.log('更新数据成功')
  }
})

// 要更新的数据对象(便捷方式)
const user = { id: 7, username: 'xxx', password: 'xxx'}
//  要执行的SQL语句
const sqlStr = 'UPDATE users SET ? WHERE id=?'
db.query(sqlStr, [user, user.id], (err, results) => {
  if(err) return console.log(err.message) //失败
  if(results.affectedRows === 1) {
    console.log('更新数据成功')
  }
})

删除数据(删)

/**
 *  删除数据 (删)
 */

// 要执行的 SQL 语句
const sqlStr = 'DELETE FROM users WHERE id=?'
db.query(sqlStr, 7, (err, results) => {
  if(err) return console.log(err.message)
  if(results.affectedRows === 1) {
    console.log('删除数据成功')
  }
})

/**
 *  标记删除(使用 UPDATE 语句  代替  DELETE 语句; 只更新数据的状态, 并没有真正删除)
 */

db.query('UPDATE USERS SET status=1 WHERE id=?', 6, (err, results) => {
  if(err) return console.log(err.message)
  if(results.affectedRows === 1) console.log('删除数据成功')
})

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

会说法语的猪

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值