Node.js

Node.js奠定了现在前端的基础 2009

Node.js概述

JavaScript语音在浏览器中需要解析运行(浏览器内核进行解析) 浏览器的内核主要包括两部分:js引擎(解析器)和渲染引擎

  • js引擎负责解析并运行JavaScript代码
  • 渲染引擎负责把HTML和CSS渲染成页面效果

浏览器除了提供js引擎之外,还提供了什么?从而方便写代码?WebAPI(DOM和BOM)

  • 为什么JavaScript可以运行在浏览器中?
    • Chrome —- V8
    • Firefox —- OdinMonkey
    • Safri —- JSCore
    • IE —- Chakra
    • etc……

image.png

总结:对于前端来说,最基础的编程语言层面需要学习:javascript语法基础;WebAPI javascript运行在浏览器的内核中js引擎(解析器) 如果没有浏览器,只有js引擎,那么js是否可以运行呢?可以

  • Node.js是什么?

image.png

  • Node.js是什么?
    • Node.js是一个开发平台,在这个平台上可以进行软件开发,并且开发出功能更加强大软件(网站),并且在这个平台上进行开发很方便,因为Node.js提供了丰富的API和优秀的运行性能。
    • 在Node.js平台中开发语言使用的依然是JavaScript
    • Node.js平台:js解析器;内置的API
    • 浏览器:js解析器;内置的API(WebAPI、内置对象Array、Date…)
  • Node.js可以做什么?
    • 服务端Web开发,就是做网站(操作数据库)
      • java、python、PHP、ruby、go……node.js
    • 服务端后台接口API项目
    • 桌面程序(基于Electron)
      • Typora
      • VSCode
      • Postman
    • 命令行工具
    • App(React Native)(IOS-swift/Android-java)
      • uniapp(vue)
      • react native
    • ……
    • javascript可能会一统江湖

Node.js开发环境配置

关于命令行用法补充

命令行:操作计算机的一种方式;另一种方式是图形界面

  • 打开命令行三种方式
    • 文件夹空白处,按住shift,右键 —> 在此处打开xxx窗口
    • windows + R,在出现的运行窗口中,输入 cmd,回车
    • 鼠标放到文件路径中,输入cmd,然后回车
  • 切换盘符命令: 盘符 + :
  1. d:
  • cd切换目录命令:cd 路径名称
  1. cd .. 切换到上一层路径
  2. cd ./01-outline 切换到当前路径下目录中
  3. cd D:\myajax\day01 切换到指定路径中
  • 查看当前目录下的文件 dir
  • 清屏命令:cls
  • 创建文件夹 mkdir 文件夹名称
  • ……

总结:命令行是一种操作计算机的方式 cd dir cls mkdir d:

安装配置Node.js环境

  • 从官网下载安装包 node-v12.18.1-x64.msi
  • 双击一直下一步完成安装
  • 如何证明安装成功了?

在命令行模式下输入 node -v 然后回车,看到版本号,证明安装成功

image.png

Node.js初体验

  1. Node.js中代码执行方式
  • 命令行窗口执行
  • 退出命令行环境的方式
    • 两次 ctrl + c
    • 输入 .exit

image.png

  1. 代码写到文件中运行
  • 必须在js文件所在的目录中运行node命令

image.png

安装可能的问题

  • Vscode内置命令行运行出现如下问题

image.png

解决方式:按照如下方式进行配置,然后重启vscode即可

image.png


  • 安装Node环境后,出现如下问题

image.png

需要配置环境变量:在【此电脑】右键->属性->高级系统设置

image.png

  • 点击环境变量-》打开的窗口中,双击Path

image.png

  • 在打开的窗口中,新建,然后把node.js的安装路径粘贴进去即可 C:\Program Files\nodejs

Node.js核心模块介绍

核心模块:主要提供如下的一些功能 核心模块提供了开箱即用的丰富的API,方便开发项目时进行调用。

  • 文件操作(文件的读写操作)
  • 网络通信(处理客户端请求并返回结果)
  • 进程管理
  • ……

image.png

总结:Node.js中提供的API(核心模块),这些模块的主要职责是提供服务 我们侧重点是接口服务(如何从后端的角度向前端提供一个接口服务?):处理网络通信;文件读写

fs模块

文件系统(File System):操作系统(windows/mac/linux)的主要职能是管理硬件和软件 磁盘(硬盘),硬盘中的数据需要管理,由操作系统的文件系统进行管理 从编程的角度,也可以通过API进行文件操作(读文件;写文件) image.png

  • fs FileSystem 文件系统模块,用于操作文件
    • 读取文件内容 fs.readFile
    • 写入文件内容 fs.writeFile
  1. /*
  2. 文件系统操作-读取文件
  3. 1、引入文件模块
  4. 2、使用模块的API操作文件
  5. */
  6. var fs = require('fs')
  7. /*
  8. 参数一:表示读取文件的路径
  9. 参数二:读取文件的编码
  10. 参数三:读取文件成功的回调函数
  11. */
  12. fs.readFile('./data.txt', 'utf-8', function (err, data) {
  13. // 参数err表示读取成功或者失败(如果err===null表示读取成功,否则err表示错误信息)
  14. // 参数data表示读取到的文件内容
  15. // 如果err是true,表示读取失败,此时一般要终止后续代码的运行
  16. if (err) return
  17. console.log(err)
  18. console.log(data)
  19. })
  1. /*
  2. 写文件操作
  3. fs.writeFile(file, data[, options], callback)
  4. */
  5. const fs = require('fs')
  6. /*
  7. 参数一表示写入文件的路径
  8. 参数二表示写入的文件内容
  9. 参数三表示写入内容的编码
  10. 参数四写入成功的回调函数
  11. */
  12. fs.writeFile('./data.json', 'hello world', 'utf8', function (err) {
  13. if (err) {
  14. // 写入文件失败
  15. console.log(err)
  16. return
  17. }
  18. console.log('写入文件成功')
  19. })
  • 读写文件的方法一般都是成对出现
    • fs.readFile
    • fs.readFileSync
    • fs.writeFile
    • fs.writeFileSync
  1. /*
  2. 同步的文件读写方法
  3. 同步的方式代码简单,但是性能不如异步的方式好
  4. */
  5. const fs = require('fs')
  6. // 采用同步的方式读取文件
  7. // let ret = fs.readFileSync('./abc.txt', 'utf8')
  8. // console.log(ret)
  9. // 采用同步的方式写文件
  10. fs.writeFileSync('./abc.txt', 'coniqiwa', 'utf8')
  11. console.log(ret)

总结:

  1. 文件读写操作都支持同步和异步方式
  2. 同步的方式性能比异步的方式要差

成绩处理案例

  • 需求:将横线之上的数据转换为横线之下的数据
    • 读取文件中原始数据,加工后写入到另一个文件中
    • \r\n 表示回车换行
    • str.replace(‘=’, ‘:’) 把等号换成冒号
  1. 小红=99 小白=100 小黄=70 小黑=66 小绿=88
  2. ------------------------------------------------
  3. 小红:99
  4. 小白:100
  5. 小黄:70
  6. 小黑:66
  7. 小绿:88
  • 功能实现
  1. // 1. 导入 fs 文件系统模块
  2. const fs = require('fs')
  3. // 2. 使用 fs.readFile() 读取 成绩.txt 文件
  4. fs.readFile('./成绩.txt', 'utf8', (err, dataStr) => {
  5. // 3. 判断文件是否读取成功
  6. if (err) {
  7. return console.log('读取文件失败!' + err.)
  8. }
  9. // 3.1 读取成功
  10. // 4. 处理成绩
  11. // 4.1 把字符串按照空格进行 split 分割
  12. const arr = dataStr.split(' ')
  13. // 4.2 循环数组,把每一项中的 = 替换成 :
  14. const newArr = []
  15. // 4.3 对原数组中的每一项进行字符串的替换操作
  16. arr.forEach(function (item) {
  17. const ite = item.replace('=', ':')
  18. // 将处理完毕的这一项,添加到新数组
  19. newArr.push(ite)
  20. })
  21. // 4.4 将新数组中的每一项,进行拼接,形成新的字符串
  22. const newStr = newArr.join('\r\n')
  23. // 5. 调用 fs.writeFile() 写入文件
  24. fs.writeFile('./成绩-ok.txt', newStr, function (err){
  25. if (err) {
  26. return console.log('文件写入失败!' + err.message)
  27. }
  28. console.log('文件写入成功!')
  29. })
  30. })
  • 方法二:
  1. const fs = require('fs')
  2. fs.readFile('./info.txt', 'utf8', function (err, score) {
  3. if (err) return
  4. // 把所有的等号替换为:
  5. let ret = score.replace(/=/g, ':')
  6. // 把上次的结果再次替换:把空格替换为回车换行
  7. ret = ret.replace(/[\s]/g, '\r\n')
  8. fs.writeFile('./result.txt', ret, 'utf-8', function (err) {
  9. if (err) return
  10. console.log('写入成功')
  11. })
  12. })
  • 同步方式读写文件
  1. // 采用同步的方式实现
  2. let data = fs.readFileSync('./scores.txt', 'utf8')
  3. let str = data.replace(/=/g, ':')
  4. str = str.replace(/\s/g, '\r\n')
  5. fs.writeFileSync('./scores2.txt', str, 'utf8')

关于文件的路径问题

  1. const fs = require('fs')
  2. // let ret = fs.readFileSync('./abc.txt', 'utf8')
  3. // ./表示命令行当前所处的路径
  4. // 我们希望文件的路径相对js文件本身来找比较方便
  5. // __dirname表示当前执行的js文件所处的路径
  6. console.log(__dirname) // D:\current\day14\02-code
  7. // 右斜杠需要做转义处理
  8. let ret = fs.readFileSync(__dirname + '\\abc.txt', 'utf8')
  9. console.log(ret)

总结:

  1. ./表示命令行当前所处的路径
  2. __dirname表示当前执行的js文件所处的路径

path模块

path模块的主要职能:操作路径

  • path.sep用法
  1. const path = require('path')
  2. const fs = require('fs')
  3. // let data = fs.readFileSync(__dirname + '\\scores.txt', 'utf8')
  4. // 如果是windows那么path.sep的值是右斜杠,如果是Linux系统,那么path.sep是左斜杠
  5. let data = fs.readFileSync(__dirname + path.sep + 'scores.txt', 'utf8')
  6. console.log(data)

总结:path.sep的作用:自动检测平台环境,根据环境自动选择斜杠类型 windows \ linux/mac/unix /

  • 拼接路径的基本用法
  1. /*
  2. 核心模块:path 路径操作
  3. 1、导入核心模块
  4. 2、使用模块相关API处理路径
  5. // path.join方法的作用:把参数中所有的路径拼接到一块并且规范化路径
  6. path.join([...paths]), 参数表示Rest参数
  7. */
  8. const path = require('path')
  9. // D:\current\day14\02-code\data.json
  10. // let p = path.join(__dirname, './data.json')
  11. // D:\current\day14\02-code\abc\hello\data.json
  12. // let p = path.join(__dirname, 'abc', 'hello', './data.json')
  13. // D:\current\day14\02-code\hello\data.json
  14. let p = path.join(__dirname, 'abc', '../hello', './data.json')
  15. console.log(p)

总结: path.join方法的作用:拼接路径并且对路径进行规范化处理

  • 路径相关方法和属性(了解)
  1. // path.parse 方法的作用:提取路径的相关信息
  2. // windows平台的路径格式
  3. // let str = 'D:\\current\\day14\\02-code\\abc\\hello\\data.json'
  4. // linux平台路径格式
  5. let str = '/home/user/dir/file.txt'
  6. let obj = path.parse(str)
  7. console.log(obj)
  8. /*
  9. {
  10. root: 'D:\\',
  11. dir: 'D:\\current\\day14\\02-code\\abc\\hello',
  12. base: 'data.json',
  13. ext: '.json',
  14. name: 'data'
  15. }
  16. */
  17. // 获取路径中的文件名称
  18. let name = path.basename(str, '.js')
  19. console.log(name)

时钟案例

  • 将html文件中的js、css代码拆解到对应得文件中,然后以链接的方式导入到HTML文件中
    • 涉及文件的读写操作
    • 如何找到要拆分的文本内容?正则匹配
  1. /*
  2. 时钟案例
  3. */
  4. // 1、读取html文件的内容
  5. const path = require('path')
  6. const fs = require('fs')
  7. // oldHtml 路径
  8. let oldHtml = path.join(__dirname, './clock.html')
  9. // newHtml 路径
  10. let newHtml = path.join(__dirname, './index.html')
  11. // js 文件路径
  12. let jsPath = path.join(__dirname, 'js', 'clock.js')
  13. // css 文件路径
  14. let cssPath = path.join(__dirname, 'css', 'clock.css')
  15. let htmlFile = fs.readFileSync(oldHtml, 'utf8')
  16. // 2、分析网页内容,拆分js和css代码
  17. // 基于正则表达式处理字符串笔记容易
  18. // 注意:小括号只是提取分组的一个作用
  19. // 匹配 <style></style>
  20. const regStyle = /<style>([\s\S]*)<\/style>/
  21. // 匹配 <script></script>
  22. const regScript = /<script>([\s\S]*)<\/script>/
  23. let cssRet = regStyle.exec(htmlFile)
  24. // 要被替换的代码
  25. let cssTagCode = cssRet[0]
  26. // 要写入文件的代码
  27. let cssCode = cssRet[1]
  28. let jsRet = regScript.exec(htmlFile)
  29. // 要被替换的代码
  30. let jsTagCode = jsRet[0]
  31. // 要写入文件的代码
  32. let jsCode = jsRet[1]
  33. // 3、把拆分出的代码分别写入对应文件并且更新链接
  34. // 3-1、写入css代码
  35. fs.writeFileSync(cssPath, cssCode, 'utf8')
  36. // 3-2、写入js代码
  37. fs.writeFileSync(jsPath, jsCode, 'utf8')
  38. // 3-3、替换html文件中的链接
  39. htmlFile = htmlFile.replace(cssTagCode, '<link rel="stylesheet" href="./css/clock.css" />')
  40. htmlFile = htmlFile.replace(jsTagCode, '<script src="./js/clock.js"></script>')
  41. // 3-4、把替换好链接的HTML页面写入文件
  42. fs.writeFileSync(newHtml, htmlFile, 'utf8')

总结:

  1. 文件读写
  2. 正则用法

总结

  • js运行在哪里?浏览器的内核中的js引擎中
  • Node.js提供了js引擎,所以js可以运行在Node.js环境中
  • 浏览器提供了:js引擎 + WebAPI
  • Node.js提供了:js引擎 + 内置API(核心模块)
  • Node.js是一个平台,可以做很多事情
  • 熟悉命令行基本操作
  • 安装Node.js的开发环境
  • Node.js代码运行方式:直接命令行写代码(了解);运行js文件
  • Node.js中的内置API和浏览器中的WebAPI做的事情不一样
  • Node.js的内置模块主要用于提供服务(给前端提供服务)
  • 关注点:提供接口服务(处理网络通信;文件读写操作)
  • 文件读写相关方法
    • fs.readFile
    • fs.readFileSync
    • fs.writeFile
    • fs.writeFileSync
  • 理解文件读写的路径问题(斜杠和拼接问题)
  • 为了更加规范的拼接路径,node提供专门的模块path
  • 重点掌握path.join方法的用法以及__dirname的作用
  • 成绩处理案例
  • 时钟案例

服务器介绍

服务器主要职能:提供服务(网页服务、视频服务、音频服务、邮箱服务。。。)数据接口服务

大量的数据资源需要存储在服务器中,客户端要想看到,需要先请求对应资源加载到客户端才能呈现出来

  • 客户端请求时,服务器的这些资源是如何返回给客户端的?(文件读取;文件写入-上传文件)
  • 服务器如何处理客户端请求?需要协议,对于这些协议,Node.js实现了相关的API,从而处理请求

总结:服务器是提供服务的,我们现在关注点是:网站服务。客户端请求服务器,服务器返回资源给浏览器。我们要从服务器提供服务的角度写代码,用于向客户端提供接口数据。

http模块

  • 服务器提供Web服务基本流程
  1. // 提供接口服务
  2. // 1、导入核心模块
  3. const http = require('http')
  4. // 2、基于http模块提供的方法实现接口服务
  5. // 2-1、创建一个服务器实例对象
  6. const server = http.createServer()
  7. // 2-2、监听端口
  8. // 3000表示端口:端口用于区分电脑中的那个网络应用程序
  9. server.listen(3000, function () {
  10. // 监听成功后,该回调函数会执行
  11. console.log('running...')
  12. })
  13. // 3、监听客户端发送的请求动作
  14. // 如果客户向3000端口发送了请求,那么如下的事件request就会触发
  15. // 那么对应的回调函数就会执行
  16. server.on('request', function (req, res) {
  17. // req表示请求对象,用于处理请求相关信息
  18. // res表示响应对象,用于处理响应相关信息
  19. // 响应客户端请求的结果
  20. res.end('hello world')
  21. })

总结:基于核心模块http实现基本的接口服务

  • 关于请求对象的两个属性的作用
    • req.url表示请求地址中的路径(端口之后的部分)
    • req.method表示客户端的请求方式(GET/POST/PUT/DELETE)
    • 后端可以根据这两个属性的组合分支判断实现多个接口
  • 接口开发流程演示
  1. /*
  2. 基于http模块实现一个接口服务
  3. */
  4. var http = require('http')
  5. var path = require('path')
  6. var fs = require('fs')
  7. // 创建一个服务器实例对象
  8. var server = http.createServer()
  9. // 监听一个端口: 0 - 65535
  10. server.listen(3000, function () {
  11. console.log('running...')
  12. })
  13. // 接收客户端的请求(当客户端有请求时,就会触发request事件)
  14. server.on('request', function (req, res) {
  15. // req表示请求对象
  16. // req.url表示请求路径
  17. // console.log(req.url)
  18. // req.method表示请求方式
  19. // console.log(req.method)
  20. // res表示响应对象
  21. // 该回调函数用于处理请求并相应合适的内容
  22. // res.end('hello nihao')
  23. if (req.url === '/getbooks' && req.method === 'GET') {
  24. // 读取文件
  25. fs.readFile(path.join(__dirname, './books-data.txt'), 'utf8', function (err, data) {
  26. if (err) {
  27. // 如果读取失败,就返回错误提示
  28. res.end('server error')
  29. }
  30. // 返回读取的数据给前端
  31. res.end(data)
  32. })
  33. } else if (req.url === '/data' && req.method === 'GET') {
  34. res.end('test data')
  35. } else {
  36. res.end('404')
  37. }
  38. })

总结:接口服务主要有两个核心流程:处理网络通信;文件读写操作

  • 设置响应数据的格式和编码
  1. // 设置响应头:告诉浏览器服务器返回的数据格式和编码是什么情况?
  2. res.setHeader('content-type', 'application/json; charset=utf8')

图书接口案例

项目基本结构

  1. /*
  2. 图书管理后端接口
  3. */
  4. var path = require('path')
  5. var fs = require('fs')
  6. var http = require('http')
  7. // 创建服务器实例对象
  8. var server = http.createServer()
  9. // 监听端口
  10. server.listen(3000, function () {
  11. console.log('running...')
  12. })
  13. // 监听客户端请求事件
  14. server.on('request', function (req, res) {
  15. if (req.url === '/books' && req.method === 'GET') {
  16. // 查询图书列表
  17. res.end('list books')
  18. } else if (req.url === '/delbook' && req.method === 'GET') {
  19. res.end('delete book')
  20. } else if (req.url === '/addbook' && req.method === 'POST') {
  21. res.end('add book')
  22. } else {
  23. res.end('404')
  24. }
  25. })

获取图书

  • 通过读取文件的方式获取图书数据
  1. // 监听客户端请求事件
  2. server.on('request', function (req, res) {
  3. if (req.url === '/books' && req.method === 'GET') {
  4. // 查询图书
  5. const filePath = path.join(__dirname, './books-data.txt')
  6. fs.readFile(filePath, 'utf-8', function (err, data) {
  7. if (err) {
  8. // 读取失败
  9. res.end('server error')
  10. return
  11. }
  12. // 正常返回数据
  13. res.end(data)
  14. })
  15. } else if (req.url === '/delbook' && req.method === 'GET') {
  16. res.end('delete book')
  17. } else if (req.url === '/addbook' && req.method === 'POST') {
  18. res.end('add book')
  19. } else {
  20. res.end('404')
  21. }
  22. })

删除图书

  • 删除图书的流程
    • 读取原始文件
    • 删除数据(处理)
    • 写会处理后结果到文件
  1. // 监听客户端请求事件
  2. server.on('request', function (req, res) {
  3. console.log(req.url)
  4. if (req.url === '/books' && req.method === 'GET') {
  5. // 查询图书列表
  6. // 从文件读取所有的图书信息
  7. var list = fs.readFileSync(path.join(__dirname, './books.json'), 'utf8')
  8. res.end(list)
  9. } else if (req.url.indexOf('/delbook') !== -1 && req.method === 'GET') {
  10. // 删除图书:
  11. // 如果是删除请求地址,那么req.url=/delbook?id=123
  12. // 获取要删除的图书的id
  13. let id = null
  14. if (req.url.indexOf('id=') !== -1) {
  15. // 获取等号字符之后一个字符的索引位置
  16. const index = req.url.lastIndexOf('=') + 1
  17. // 截取索引之后的字符串(包括索引)
  18. id = req.url.substring(index)
  19. }
  20. if (id === null) {
  21. // 前端没有传递id值
  22. res.end('请传递图书id')
  23. return
  24. }
  25. // 删除图书:
  26. // 1、读取所有的文件数据
  27. const filePath = path.join(__dirname, './books-data.txt')
  28. const books = fs.readFileSync(filePath, 'utf8')
  29. // 2、把读取到的数据删除一条(根据id删除)
  30. // 把字符串books转换为对象
  31. let booksArr = JSON.parse(books)
  32. booksArr = booksArr.filter(function (item) {
  33. console.log(item.id !== parseInt(id))
  34. return item.id !== parseInt(id)
  35. })
  36. // 3、把剩余数据写回文件中
  37. fs.writeFileSync(filePath, JSON.stringify(booksArr), 'utf8')
  38. // 4、返回状态信息
  39. res.end(JSON.stringify({
  40. status: 0,
  41. message: '删除图书成功'
  42. }))
  43. } else if (req.url === '/addbook' && req.method === 'POST') {
  44. res.end('add book')
  45. } else {
  46. res.end('404')
  47. }
  48. })

总结:监听前端的请求,操作文件、响应状态

  1. 获取请求参数
  2. 删除的流程:读文件;操作数组;写文件