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……
总结:对于前端来说,最基础的编程语言层面需要学习:javascript语法基础;WebAPI javascript运行在浏览器的内核中js引擎(解析器) 如果没有浏览器,只有js引擎,那么js是否可以运行呢?可以
- Node.js是什么?
- 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可能会一统江湖
- 服务端Web开发,就是做网站(操作数据库)
Node.js开发环境配置
关于命令行用法补充
命令行:操作计算机的一种方式;另一种方式是图形界面
- 打开命令行三种方式
- 文件夹空白处,按住shift,右键 —> 在此处打开xxx窗口
- windows + R,在出现的运行窗口中,输入 cmd,回车
- 鼠标放到文件路径中,输入cmd,然后回车
- 切换盘符命令: 盘符 + :
d:
- cd切换目录命令:cd 路径名称
cd .. 切换到上一层路径
cd ./01-outline 切换到当前路径下目录中
cd D:\myajax\day01 切换到指定路径中
- 查看当前目录下的文件 dir
- 清屏命令:cls
- 创建文件夹 mkdir 文件夹名称
- ……
总结:命令行是一种操作计算机的方式 cd dir cls mkdir d:
安装配置Node.js环境
- 从官网下载安装包 node-v12.18.1-x64.msi
- 双击一直下一步完成安装
- 如何证明安装成功了?
在命令行模式下输入 node -v 然后回车,看到版本号,证明安装成功
Node.js初体验
- Node.js中代码执行方式
- 命令行窗口执行
- 退出命令行环境的方式
- 两次 ctrl + c
- 输入 .exit
- 代码写到文件中运行
- 必须在js文件所在的目录中运行node命令
安装可能的问题
- Vscode内置命令行运行出现如下问题
解决方式:按照如下方式进行配置,然后重启vscode即可
- 安装Node环境后,出现如下问题
需要配置环境变量:在【此电脑】右键->属性->高级系统设置
- 点击环境变量-》打开的窗口中,双击Path
- 在打开的窗口中,新建,然后把node.js的安装路径粘贴进去即可 C:\Program Files\nodejs
Node.js核心模块介绍
核心模块:主要提供如下的一些功能 核心模块提供了开箱即用的丰富的API,方便开发项目时进行调用。
- 文件操作(文件的读写操作)
- 网络通信(处理客户端请求并返回结果)
- 进程管理
- ……
总结:Node.js中提供的API(核心模块),这些模块的主要职责是提供服务 我们侧重点是接口服务(如何从后端的角度向前端提供一个接口服务?):处理网络通信;文件读写
fs模块
文件系统(File System):操作系统(windows/mac/linux)的主要职能是管理硬件和软件 磁盘(硬盘),硬盘中的数据需要管理,由操作系统的文件系统进行管理 从编程的角度,也可以通过API进行文件操作(读文件;写文件)
- fs FileSystem 文件系统模块,用于操作文件
- 读取文件内容 fs.readFile
- 写入文件内容 fs.writeFile
/*
文件系统操作-读取文件
1、引入文件模块
2、使用模块的API操作文件
*/
var fs = require('fs')
/*
参数一:表示读取文件的路径
参数二:读取文件的编码
参数三:读取文件成功的回调函数
*/
fs.readFile('./data.txt', 'utf-8', function (err, data) {
// 参数err表示读取成功或者失败(如果err===null表示读取成功,否则err表示错误信息)
// 参数data表示读取到的文件内容
// 如果err是true,表示读取失败,此时一般要终止后续代码的运行
if (err) return
console.log(err)
console.log(data)
})
/*
写文件操作
fs.writeFile(file, data[, options], callback)
*/
const fs = require('fs')
/*
参数一表示写入文件的路径
参数二表示写入的文件内容
参数三表示写入内容的编码
参数四写入成功的回调函数
*/
fs.writeFile('./data.json', 'hello world', 'utf8', function (err) {
if (err) {
// 写入文件失败
console.log(err)
return
}
console.log('写入文件成功')
})
- 读写文件的方法一般都是成对出现
- fs.readFile
- fs.readFileSync
- fs.writeFile
- fs.writeFileSync
/*
同步的文件读写方法
同步的方式代码简单,但是性能不如异步的方式好
*/
const fs = require('fs')
// 采用同步的方式读取文件
// let ret = fs.readFileSync('./abc.txt', 'utf8')
// console.log(ret)
// 采用同步的方式写文件
fs.writeFileSync('./abc.txt', 'coniqiwa', 'utf8')
console.log(ret)
总结:
- 文件读写操作都支持同步和异步方式
- 同步的方式性能比异步的方式要差
成绩处理案例
- 需求:将横线之上的数据转换为横线之下的数据
- 读取文件中原始数据,加工后写入到另一个文件中
- \r\n 表示回车换行
- str.replace(‘=’, ‘:’) 把等号换成冒号
小红=99 小白=100 小黄=70 小黑=66 小绿=88
------------------------------------------------
小红:99
小白:100
小黄:70
小黑:66
小绿:88
- 功能实现
// 1. 导入 fs 文件系统模块
const fs = require('fs')
// 2. 使用 fs.readFile() 读取 成绩.txt 文件
fs.readFile('./成绩.txt', 'utf8', (err, dataStr) => {
// 3. 判断文件是否读取成功
if (err) {
return console.log('读取文件失败!' + err.)
}
// 3.1 读取成功
// 4. 处理成绩
// 4.1 把字符串按照空格进行 split 分割
const arr = dataStr.split(' ')
// 4.2 循环数组,把每一项中的 = 替换成 :
const newArr = []
// 4.3 对原数组中的每一项进行字符串的替换操作
arr.forEach(function (item) {
const ite = item.replace('=', ':')
// 将处理完毕的这一项,添加到新数组
newArr.push(ite)
})
// 4.4 将新数组中的每一项,进行拼接,形成新的字符串
const newStr = newArr.join('\r\n')
// 5. 调用 fs.writeFile() 写入文件
fs.writeFile('./成绩-ok.txt', newStr, function (err){
if (err) {
return console.log('文件写入失败!' + err.message)
}
console.log('文件写入成功!')
})
})
- 方法二:
const fs = require('fs')
fs.readFile('./info.txt', 'utf8', function (err, score) {
if (err) return
// 把所有的等号替换为:
let ret = score.replace(/=/g, ':')
// 把上次的结果再次替换:把空格替换为回车换行
ret = ret.replace(/[\s]/g, '\r\n')
fs.writeFile('./result.txt', ret, 'utf-8', function (err) {
if (err) return
console.log('写入成功')
})
})
- 同步方式读写文件
// 采用同步的方式实现
let data = fs.readFileSync('./scores.txt', 'utf8')
let str = data.replace(/=/g, ':')
str = str.replace(/\s/g, '\r\n')
fs.writeFileSync('./scores2.txt', str, 'utf8')
关于文件的路径问题
const fs = require('fs')
// let ret = fs.readFileSync('./abc.txt', 'utf8')
// ./表示命令行当前所处的路径
// 我们希望文件的路径相对js文件本身来找比较方便
// __dirname表示当前执行的js文件所处的路径
console.log(__dirname) // D:\current\day14\02-code
// 右斜杠需要做转义处理
let ret = fs.readFileSync(__dirname + '\\abc.txt', 'utf8')
console.log(ret)
总结:
- ./表示命令行当前所处的路径
- __dirname表示当前执行的js文件所处的路径
path模块
path模块的主要职能:操作路径
- path.sep用法
const path = require('path')
const fs = require('fs')
// let data = fs.readFileSync(__dirname + '\\scores.txt', 'utf8')
// 如果是windows那么path.sep的值是右斜杠,如果是Linux系统,那么path.sep是左斜杠
let data = fs.readFileSync(__dirname + path.sep + 'scores.txt', 'utf8')
console.log(data)
总结:path.sep的作用:自动检测平台环境,根据环境自动选择斜杠类型 windows \ linux/mac/unix /
- 拼接路径的基本用法
/*
核心模块:path 路径操作
1、导入核心模块
2、使用模块相关API处理路径
// path.join方法的作用:把参数中所有的路径拼接到一块并且规范化路径
path.join([...paths]), 参数表示Rest参数
*/
const path = require('path')
// D:\current\day14\02-code\data.json
// let p = path.join(__dirname, './data.json')
// D:\current\day14\02-code\abc\hello\data.json
// let p = path.join(__dirname, 'abc', 'hello', './data.json')
// D:\current\day14\02-code\hello\data.json
let p = path.join(__dirname, 'abc', '../hello', './data.json')
console.log(p)
总结: path.join方法的作用:拼接路径并且对路径进行规范化处理
- 路径相关方法和属性(了解)
// path.parse 方法的作用:提取路径的相关信息
// windows平台的路径格式
// let str = 'D:\\current\\day14\\02-code\\abc\\hello\\data.json'
// linux平台路径格式
let str = '/home/user/dir/file.txt'
let obj = path.parse(str)
console.log(obj)
/*
{
root: 'D:\\',
dir: 'D:\\current\\day14\\02-code\\abc\\hello',
base: 'data.json',
ext: '.json',
name: 'data'
}
*/
// 获取路径中的文件名称
let name = path.basename(str, '.js')
console.log(name)
时钟案例
- 将html文件中的js、css代码拆解到对应得文件中,然后以链接的方式导入到HTML文件中
- 涉及文件的读写操作
- 如何找到要拆分的文本内容?正则匹配
/*
时钟案例
*/
// 1、读取html文件的内容
const path = require('path')
const fs = require('fs')
// oldHtml 路径
let oldHtml = path.join(__dirname, './clock.html')
// newHtml 路径
let newHtml = path.join(__dirname, './index.html')
// js 文件路径
let jsPath = path.join(__dirname, 'js', 'clock.js')
// css 文件路径
let cssPath = path.join(__dirname, 'css', 'clock.css')
let htmlFile = fs.readFileSync(oldHtml, 'utf8')
// 2、分析网页内容,拆分js和css代码
// 基于正则表达式处理字符串笔记容易
// 注意:小括号只是提取分组的一个作用
// 匹配 <style></style>
const regStyle = /<style>([\s\S]*)<\/style>/
// 匹配 <script></script>
const regScript = /<script>([\s\S]*)<\/script>/
let cssRet = regStyle.exec(htmlFile)
// 要被替换的代码
let cssTagCode = cssRet[0]
// 要写入文件的代码
let cssCode = cssRet[1]
let jsRet = regScript.exec(htmlFile)
// 要被替换的代码
let jsTagCode = jsRet[0]
// 要写入文件的代码
let jsCode = jsRet[1]
// 3、把拆分出的代码分别写入对应文件并且更新链接
// 3-1、写入css代码
fs.writeFileSync(cssPath, cssCode, 'utf8')
// 3-2、写入js代码
fs.writeFileSync(jsPath, jsCode, 'utf8')
// 3-3、替换html文件中的链接
htmlFile = htmlFile.replace(cssTagCode, '<link rel="stylesheet" href="./css/clock.css" />')
htmlFile = htmlFile.replace(jsTagCode, '<script src="./js/clock.js"></script>')
// 3-4、把替换好链接的HTML页面写入文件
fs.writeFileSync(newHtml, htmlFile, 'utf8')
总结:
- 文件读写
- 正则用法
总结
- 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、导入核心模块
const http = require('http')
// 2、基于http模块提供的方法实现接口服务
// 2-1、创建一个服务器实例对象
const server = http.createServer()
// 2-2、监听端口
// 3000表示端口:端口用于区分电脑中的那个网络应用程序
server.listen(3000, function () {
// 监听成功后,该回调函数会执行
console.log('running...')
})
// 3、监听客户端发送的请求动作
// 如果客户向3000端口发送了请求,那么如下的事件request就会触发
// 那么对应的回调函数就会执行
server.on('request', function (req, res) {
// req表示请求对象,用于处理请求相关信息
// res表示响应对象,用于处理响应相关信息
// 响应客户端请求的结果
res.end('hello world')
})
总结:基于核心模块http实现基本的接口服务
- 关于请求对象的两个属性的作用
- req.url表示请求地址中的路径(端口之后的部分)
- req.method表示客户端的请求方式(GET/POST/PUT/DELETE)
- 后端可以根据这两个属性的组合分支判断实现多个接口
- 接口开发流程演示
/*
基于http模块实现一个接口服务
*/
var http = require('http')
var path = require('path')
var fs = require('fs')
// 创建一个服务器实例对象
var server = http.createServer()
// 监听一个端口: 0 - 65535
server.listen(3000, function () {
console.log('running...')
})
// 接收客户端的请求(当客户端有请求时,就会触发request事件)
server.on('request', function (req, res) {
// req表示请求对象
// req.url表示请求路径
// console.log(req.url)
// req.method表示请求方式
// console.log(req.method)
// res表示响应对象
// 该回调函数用于处理请求并相应合适的内容
// res.end('hello nihao')
if (req.url === '/getbooks' && req.method === 'GET') {
// 读取文件
fs.readFile(path.join(__dirname, './books-data.txt'), 'utf8', function (err, data) {
if (err) {
// 如果读取失败,就返回错误提示
res.end('server error')
}
// 返回读取的数据给前端
res.end(data)
})
} else if (req.url === '/data' && req.method === 'GET') {
res.end('test data')
} else {
res.end('404')
}
})
总结:接口服务主要有两个核心流程:处理网络通信;文件读写操作
- 设置响应数据的格式和编码
// 设置响应头:告诉浏览器服务器返回的数据格式和编码是什么情况?
res.setHeader('content-type', 'application/json; charset=utf8')
图书接口案例
项目基本结构
/*
图书管理后端接口
*/
var path = require('path')
var fs = require('fs')
var http = require('http')
// 创建服务器实例对象
var server = http.createServer()
// 监听端口
server.listen(3000, function () {
console.log('running...')
})
// 监听客户端请求事件
server.on('request', function (req, res) {
if (req.url === '/books' && req.method === 'GET') {
// 查询图书列表
res.end('list books')
} else if (req.url === '/delbook' && req.method === 'GET') {
res.end('delete book')
} else if (req.url === '/addbook' && req.method === 'POST') {
res.end('add book')
} else {
res.end('404')
}
})
获取图书
- 通过读取文件的方式获取图书数据
// 监听客户端请求事件
server.on('request', function (req, res) {
if (req.url === '/books' && req.method === 'GET') {
// 查询图书
const filePath = path.join(__dirname, './books-data.txt')
fs.readFile(filePath, 'utf-8', function (err, data) {
if (err) {
// 读取失败
res.end('server error')
return
}
// 正常返回数据
res.end(data)
})
} else if (req.url === '/delbook' && req.method === 'GET') {
res.end('delete book')
} else if (req.url === '/addbook' && req.method === 'POST') {
res.end('add book')
} else {
res.end('404')
}
})
删除图书
- 删除图书的流程
- 读取原始文件
- 删除数据(处理)
- 写会处理后结果到文件
// 监听客户端请求事件
server.on('request', function (req, res) {
console.log(req.url)
if (req.url === '/books' && req.method === 'GET') {
// 查询图书列表
// 从文件读取所有的图书信息
var list = fs.readFileSync(path.join(__dirname, './books.json'), 'utf8')
res.end(list)
} else if (req.url.indexOf('/delbook') !== -1 && req.method === 'GET') {
// 删除图书:
// 如果是删除请求地址,那么req.url=/delbook?id=123
// 获取要删除的图书的id
let id = null
if (req.url.indexOf('id=') !== -1) {
// 获取等号字符之后一个字符的索引位置
const index = req.url.lastIndexOf('=') + 1
// 截取索引之后的字符串(包括索引)
id = req.url.substring(index)
}
if (id === null) {
// 前端没有传递id值
res.end('请传递图书id')
return
}
// 删除图书:
// 1、读取所有的文件数据
const filePath = path.join(__dirname, './books-data.txt')
const books = fs.readFileSync(filePath, 'utf8')
// 2、把读取到的数据删除一条(根据id删除)
// 把字符串books转换为对象
let booksArr = JSON.parse(books)
booksArr = booksArr.filter(function (item) {
console.log(item.id !== parseInt(id))
return item.id !== parseInt(id)
})
// 3、把剩余数据写回文件中
fs.writeFileSync(filePath, JSON.stringify(booksArr), 'utf8')
// 4、返回状态信息
res.end(JSON.stringify({
status: 0,
message: '删除图书成功'
}))
} else if (req.url === '/addbook' && req.method === 'POST') {
res.end('add book')
} else {
res.end('404')
}
})
总结:监听前端的请求,操作文件、响应状态
- 获取请求参数
- 删除的流程:读文件;操作数组;写文件