文章目录
Node.js(后台语言)
一. 浏览器中JavaScript与Node.js中的JavaScript
1.1 浏览器JavaScript组成部分
- ECMAScript 核心
- BOM -> window
- DOM -> document
1.2 Node.js中的JavaScript组成部分
- ECMAScript 核心
- 全局成员
- 核心API成员
- Node.js中没有BOM和DOM的概念
由于Node服务器端运行环境中,没有浏览器和HTML的概念,所以Node中剔除了DOM和BOM对象模型,取而代之的是全局成员和核心API模块
1.3 之间的关系与区别
- ECMAScript 规范(标准):就是一般书,这本书规定了语言特性
- 浏览器中的js:
- 浏览器中的js组成部分:ECMAScript核心+DOM+BOM
- Node中的js:
- Node中的js组成部分:ECMAScript核心+全局成员+核心API成员
[外链图片转存失败(img-vsvy2pol-1566292781251)(en-resource://database/1401:1)]
- Node中的js组成部分:ECMAScript核心+全局成员+核心API成员
二. 环境安装*
LTS和Current版本区别
- LTS:【推荐在企业中使用】,是长期稳定版的安装包,运行稳定、安全;
- Current:【推荐学习或尝鲜去使用】,是最新特征版,这个安装包中有最新的Node特性
三. 快捷操作
- TAB 自动补全
C:\Users\阿怼\Desktop> node .\node.js
- ↑ 返回上一条命令
- 右键 粘贴所复制的内容
cls
清屏node
进入REPL环境 按 Ctrl+C 两次退出node -v
检查Node版本,也可检查Node是否安装成功cd
路径 到…文件夹路径cd..
返回上一级路径
四. Node中的核心模块(核心API成员)
使用模块前需要先调用
const
设定为常量
const 名称 = require('核心模块名');
4.1 fs-文件系统
fs
模块提供了一个 API,用于以模仿标准 POSIX 函数的方式与文件系统进行交互。要使用此模块:
(要先调用)
const fs = require('fs');
4.1.1 读取文件内容
fs.readFile(path[, options], callback)
path
| | | 文件名或文件描述符,文件路径–表示要读取的文件路径options
| –表示要一什么样的编码格式,来都读取指定的文件,默认编码格式为NULL- encoding | 默认值: null。编码格式
- flag – 读/写 权限
callback
--表示当文件读取完成用callback函数处理- err – 错误
- data |
const fs = require('fs')
fs.readFile('./1.txt', 'utf-8', function(err, data) {
if (err) {
console.log('读取错误:' + err.message);
}
console.log('读取成功' + data);
})
4.1.2 写入文件内容
fs.writeFile(file, data[, options], callback)
- file | | | 文件名或文件描述符。–路径字符串
- data | | | –要写入的数据 可以给定一个字符串
- options | –写入文件格式
- encoding | 默认值: ‘utf8’。
- mode 默认值: 0o666。
- flag 参阅支持的文件系统标志。默认值: ‘w’。
- callback
- err
异步地将数据写入到一个文件,如果文件已存在则覆盖该文件。 data 可以是字符串或 buffer。
const fs = require('fs')
fs.writeFile('./2.txt', '嘿嘿嘿', function(err) {
if (err) return console.log('写入错误:' + err.message)
console.log('写入成功');
})
4.1.3 追加文件内容
fs.appendFile(path, data[, options], callback)
- path | | | 文件名或文件描述符。
- data |
- options |
- encoding | 默认值: ‘utf8’。
- mode 默认值: 0o666。
- flag 参阅支持的文件系统标志。默认值: ‘a’。
- callback err
异步地将数据追加到文件,如果文件尚不存在则创建该文件。 data 可以是字符串或 Buffer。
const fs = require('fs')
fs.appendFile('./2.txt', '\n嘻嘻嘻', (err)=> {
if (err) return console.log('追加错误:' + err.message)
console.log('追加成功');
})
4.1.4 模块中路径操作问题*
使用 fs 模块操作文件的时候,如果提供的操作路径是 相对路径, 则会根据当前执行node命令时的磁盘目录,去拼接提供的文件的相对路径,从而容易出现问题;例如:
const fs = require('fs')
// 调用 fs.readFile 方法时,提供的第一个参数是相对路径,容易出现问题
fs.readFile('./files/1.txt', 'utf-8', (err, data) => {
if(err) return console.log(err.message)
console.log(data)
})
- 推荐使用 node 中提供的
__dirname
来解决 fs 模块操作文件时候的路径问题__dirname
表示当前这个文件所在的磁盘目录
const fs = require('fs')
fs.readFile(__dirname + '/1.txt', 'utf-8', (err, data) => {
if (err) return console.log(err.message)
console.log('文件内容为:' + data)
console.log('磁盘目录为:' + __dirname)
console.log('文件路径为:' + __dirname + '/1.txt')
})
// 文件内容为:哈哈哈哈哈
// 磁盘目录为:C:\黑马程序员\就业班\笔记\node.js
// 文件路径为:C:\黑马程序员\就业班\笔记\node.js/1.txt
补充:
__dirname
表示当前这个文件执行的时候所处的根目录,只代表一层目录而已(可变)
__filename
表示当前这个文件执行的时候的完整路径,包含了具体文件名
4.1.5 读取文件信息
fs.Stats
对象提供有关文件的信息。
fs.stat(path[, options], callback)
- path | |
- options
- bigint 返回的 fs.Stats 对象中的数值是否应为 bigint 型。默认值: false。
- callback
- err
- stats <fs.Stats>
- 异步的
stat(2)
。 回调有两个参数(err, stats)
,其中stats
是fs.Stats
。 - 如果出现错误,则
err.code
将是常见系统错误之一。 - 不建议在调用
fs.open()
、fs.readFile()
或fs.writeFile()
之前使用fs.stat()
检查文件是否存在。 而是应该直接打开、读取或写入文件,如果文件不可用则处理引发的错误。 - 要检查文件是否存在但随后并不对其进行操作,则建议使用
fs.access()
。
const fs = require('fs')
fs.stat(__dirname + '/1.txt', (err, stats) => {
if (err) return console.log(err.message)
// 大小
console.log(stats.size);
// 创建时间
console.log(stats.birthtime);
// 是否为文件
console.log(stats.isFile());
// 是否为目录
console.log(stats.isDirectory());
})
// 15
// 2019-07-19T01:14:02.809Z
// true
// false
Stats
返回信息
const fs = require('fs')
fs.stat(__dirname + '/1.txt', (err, stats) => {
if (err) return console.log(err.message)
console.log(stats);
})
// 返回文件信息(对象)
Stats {
dev: 1381884629,
mode: 33206,
nlink: 1,
uid: 0,
gid: 0,
rdev: 0,
blksize: 4096,
ino: 15481123719203076,
size: 15,
blocks: 0,
atimeMs: 1563498842809.0007,
mtimeMs: 1563503649468.5012,
ctimeMs: 1563503649468.5012,
birthtimeMs: 1563498842809.0007,
atime: 2019-07-19T01:14:02.809Z,
mtime: 2019-07-19T02:34:09.469Z,
ctime: 2019-07-19T02:34:09.469Z,
birthtime: 2019-07-19T01:14:02.809Z
}
4.1.6 复制文件
fs.copyFile(src, dest[, flags], callback)
- src | | 要拷贝的源文件名。
- dest | | 拷贝操作的目标文件名。
- flags 用于拷贝操作的修饰符。默认值: 0。
- callback
异步地将
src
拷贝到dest
。 默认情况下,如果dest
已经存在,则覆盖它。 除了可能的异常,回调函数没有其他参数。 Node.js 不保证拷贝操作的原子性。 如果在打开目标文件用于写入后发生错误,则 Node.js 将尝试删除目标文件。
- flags 是一个可选的整数,指定拷贝操作的行为。 可以创建由两个或更多个值按位或组成的掩码(比如
fs.constants.COPYFILE_EXCL
|fs.constants.COPYFILE_FICLONE
)。fs.constants.COPYFILE_EXCL
- 如果dest
已存在,则拷贝操作将失败。fs.constants.COPYFILE_FICLONE
- 拷贝操作将尝试创建写时拷贝(copy-on-write)链接。如果平台不支持写时拷贝,则使用后备的拷贝机制。fs.constants.COPYFILE_FICLONE_FORCE
- 拷贝操作将尝试创建写时拷贝链接。如果平台不支持写时拷贝,则拷贝操作将失败。
const fs = require('fs')
fs.copyFile(__dirname + '/1.txt', __dirname + '/1-copy.txt', (err) => {
if (err) return console.log(err.message)
console.log('copy成功');
})
4.2 path - 路径
path
模块提供用于处理文件路径和目录路径的实用工具。 它可以使用以下方式访问:
const path = require('path');
4.2.1 path.join([…paths]) –拼接路径
...paths
路径片段的序列。- 返回:
path.join()
方法使用平台特定的分隔符作为定界符将所有给定的path
片段连接在一起,然后规范化生成的路径。- 零长度的
path
片段会被忽略。 如果连接的路径字符串是零长度的字符串,则返回'.'
,表示当前工作目录。
path.join('/foo', 'bar', 'baz/asdf', 'quux', '..');
// 返回: '/foo/bar/baz/asdf'
path.join('foo', {}, 'bar');
// 抛出 'TypeError: Path must be a string. Received {}'
// 应用
fs.readFile(path.jion(__dirname , './1.txt'), 'utf-8', (err, data) => {
if (err) return console.log(err.message)
console.log('文件内容为:' + data)
})
4.2.2 path.sep –路径分隔符
'foo/bar/baz'.split(path.sep);
// 返回: ['foo', 'bar', 'baz']
'foo\\bar\\baz'.split(path.sep);
// 返回: ['foo', 'bar', 'baz']
4.2.3 path.basename(path[, ext]) –获取文件名称
- path
- ext 可选的文件扩展名。
- 返回:
path.basename()
方法返回path
的最后一部分,类似于 Unix 的basename
命令。
path.basename('/foo/bar/baz/asdf/quux.html');
// 返回: 'quux.html'
path.basename('/foo/bar/baz/asdf/quux.html', '.html');
// 返回: 'quux'
4.2.4 path.dirname(path) –获取文件所在的路径
- path
- 返回:
- path.dirname() 方法返回 path 的目录名,类似于 Unix 的 dirname 命令。
path.dirname('/foo/bar/baz/asdf/quux');
// 返回: '/foo/bar/baz/asdf'
4.2.5 path.extname(path) –获取文件的扩展名
- path
- 返回:
path.extname()
方法返回path
的扩展名,从最后一次出现 .(句点)字符到 path 最后一部分的字符串结束。 如果在path
的最后一部分中没有.
,或者如果path
的基本名称(参阅path.basename()
)除了第一个字符以外没有 .,则返回空字符串。
path.extname('index.html');
// 返回: '.html'
path.extname('index.coffee.md');
// 返回: '.md'
path.extname('index.');
// 返回: '.'
path.extname('index');
// 返回: ''
path.extname('.index');
// 返回: ''
path.extname('.index.md');
// 返回: '.md'
集合展示
const path = require('path')
// console.log(path.sep) // 路径分隔符
const str = 'c:/a/b/c/1.txt'
console.log(path.basename(str))
// 获取文件名称的
console.log(path.dirname(str))
// 获取文件所在的路径的
console.log(path.extname(str))
// 获取文件的扩展名
4.3 http - HTTP
创建WEB基本服务器
// 导入http核心模块
const http = require('http')
// 调用http.createServer()方法,创建一个服务器对象
const server = http.createServer()
// 为server服务器绑定监听函数,通过 on 方法,绑定request事件,来监听客户的请求
// req 表示客户端相关的参数
// res 表示和服务器相关的参数和方法
server.on("request", function(req, res) {
// 设置响应头 解决中文乱码 状态码:200
res.writeHeader(200, {
'Content-Type': 'text/plain;charset=utf-8'
})
res.end('哈哈哈')
})
// 启动服务器
server.listen(3000, '127.0.0.1', function() {
console.log('server running at http://127.0.0.1:3000')
})
4.4 querystring - 查询字符串
querystring
模块提供用于解析和格式化 URL 查询字符串的实用工具
const querystring = require('querystring');
querystring.parse(str[, sep[, eq[, options]]])
str
要解析的 URL 查询字符串。sep
用于在查询字符串中分隔键值对的子字符串。默认值:'&'
。eq
用于在查询字符串中分隔键和值的子字符串。默认值:'='
。
*options
decodeURIComponent
解码查询字符串中的百分比编码字符时使用的函数。默认值:querystring.unescape()
。maxKeys
指定要解析的键的最大数量。指定0
可移除键的计数限制。默认值:1000
。
querystring.parse()
方法将 URL 查询字符串 str 解析为键值对的集合。
例如,查询字符串 'foo=bar&abc=xyz&abc=123'
被解析为:
{
foo: 'bar',
abc: ['xyz', '123']
}
五. Node.js 中模块和包的概念
5.1 模块成员分类
模块成员,根据一些区别可以分为三类
- 核心模块
require('核心模块标识符')
Node.js 安装时 全部附带安装- 第三方模块
require('第三方模块标识符')
在npm上下载的模块- 用户自定义模块
require('路径标识符')
程序猿自己写的js文件
5.2 包的定义和使用
5.2.1 什么是包
- 英文名叫做
Packages
,包是在模块基础上更深一步的抽象; - 包的目的:方便分发和推广基于
CommonJS
规范实现的 应用程序 或 类库; - 包可以看作是 模块、代码 和 其它资源 组合起来形成的 独立作用域
5.2.2 规范的包结构
- 包都要以一个单独的目录而存在;
package.json
必须在包的顶层目录下;package.json
文件必须符合 JSON 格式,并且必须包含如下三个属性:name, version, main- name: 包的名字
- version: 包的版本号
- main: 表示包的入口文件
- 二进制文件应该在bin目录下;
- javaScript代码应该在lib目录下;
- 文档应该在doc目录下;
- 单元测试应该在test目录下;
- Node.js对包要求并没有那么严格,只要顶层目录下有package.json,并符合基本规范即可;
[外链图片转存失败(img-Lo5jdwrT-1566292781252)(en-resource://database/1439:1)]
5.2.3 包描述文件 package.json【了解】
name:包的名称,必须是唯一
description:包的简要说明
version:符合语义化版本识别规范的版本字符串
keywords:关键字数据,通常用于搜索
maintainers:维护者数组,每个元素要包含name、email、web可选字段
contributors:贡献者数组,格式与maintainers相同。包的坐着应该是贡献者数据的第一个元素
bugs:提交bug的地址,可以是网址或者电子邮件地址
licenses:许可证数组,每个元素要包含type和url字段
repositories:仓库托管地址数组,每个元素要包含type、url和path字段
dependencies:包的依赖,一个关联数组,由包名称和版本号组成。
devDependencies:开发依赖项,表示一个包在开发期间用到的依赖项
5.3 中间件
在 Node.js 中被广泛使用,它泛指一种特定的设计模式、一系列的处理单元、过滤器和处理程序,以函数的形式存在,连接在一起,形成一个异步队列,来完成对任何数据的预处理和后处理。
它的优点在于 灵活性:使用中间件我们用极少的操作就能得到一个插件,用最简单的方法就能将新的过滤器和处理程序扩展到现有的系统上。
[外链图片转存失败(img-48C8RC6r-1566292781253)(en-resource://database/1441:1)]
六. 第三方模块/框架
6.1 express框架 – 开发API接口
6.1.1 表达()
创建
Express
应用程序。该express()
函数是express模块
导出的顶级函数。
const express = require('express');
const app = express();
6.1.2 创建一个基本的服务器
// 导入express
const express = require('express');
// 调用express()创建服务器
const app = express();
// 调用app.get()方法,监听客户端的请求,并指定要监听的URL地址和处理函数
app.get('/', (req, res)=>{
res.send('hello world');
});
// 调用app.listen() 方法启动服务器
app.listen(3000,()=>{
console.log('serve running at http://127.0.0.1:3000');
});
6.1.3 应用(app)
- app.get(path,callback [,callback …])
- 使用指定的回调函数将HTTP GET请求路由到指定的路径。
app.get('/', function (req, res) {
res.send('GET request to homepage');});
- app.post(path,callback [,callback …])
- 使用指定的回调函数将HTTP POST请求路由到指定的路径。
app.post('/', function (req, res) {
res.send('POST request to homepage');});
- app.set()
- app.arguments()
- app.static()
6.1.4 响应 (res)
1.res.send([body])
- 发送HTTP响应。
res.send(new Buffer('whoop'));
res.send({ some: 'json' });
res.send('<p>some html</p>');
res.status(404).send('Sorry, we cannot find that!');
res.status(500).send({ error: 'something blew up' });
res.sendFile(path [,options] [,fn])
- 在给定的时间传输文件
path
。Content-Type
根据文件名的扩展名设置响应HTTP标头字段。除非root
在options
对象中设置了该选项,path
否则必须是该文件的绝对路径。
- 在给定的时间传输文件
app.get('/file/:name', function (req, res, next) {
var options = {
root: __dirname + '/public/',
dotfiles: 'deny',
headers: {
'x-timestamp': Date.now(),
'x-sent': true
}
};
var fileName = req.params.name;
res.sendFile(fileName, options, function (err) {
if (err) {
next(err);
} else {
console.log('Sent:', fileName);
}
});
});
const express = require('express')
const path = require('path')
const app = express()
app.get('/', (req, res) => {
// 1. 注意:sendFile 如果只给定一个参数的时候,这个参数必须是绝对路径,表示要发送给客户端的文件的路径
// res.sendFile('./views/home.html')
// res.sendFile(path.join(__dirname, './views/home.html'))
// 2. 为 res.sendFile 方法,提供两个参数进行调用
// 第一个实参就可以传递一个相对路径了;第二个实参,必须是一个绝对路径;
res.sendFile('./views/home.html', { root: __dirname })
})
app.get('/movie', (req, res) => {
res.sendFile('./views/movie.html', { root: __dirname })
})
app.get('/about', (req, res) => {
res.sendFile('./views/about.html', { root: __dirname })
})
app.listen(3000, () => {
console.log('server running at http://127.0.0.1:3000')
})
6.1.5 快速托管静态资源
express.static(root,[options])
这是Express
中的内置中间件功能。它提供静态文件,基于 serve-static
。
该
root
参数指定从中提供静态资产的根目录。该函数通过req.url
与提供的root目录组合来确定要提供的文件。当找不到文件时,它不是发送404响应,而是调用next()
继续下一个中间件,允许堆叠和回退。
- 语法1:
app.use(express.static('public'))
;app.use()
方法,是专门用来注册 中间件;express.static
是express的内置中间件;
- 语法2:
app.use('/虚拟目录', express.static('public'))
const express = require('express')
const app = express()
// app.use() 的作用,就是注册中间件
// express.static() 方法,可以把 指定的 目录,托管为静态资源目录,这样,指定目录下的所有文件,
// 都可以直接被 浏览器来访问
// app.use(express.static('./views'))
// 可以在托管静态资源文件的时候,指定要挂载的虚拟路径;
app.use('/page', express.static('./views'))
app.listen(3000, () => {
console.log('server running at http://127.0.0.1:3000')
})
6.1.6 为 express框架配置模板引擎渲染动态页面
使用ejs模板引擎
- 安装 ejs 模板引擎
npm i ejs -S
- 使用
app.set()
配置默认的模板引擎app.set('view engine', 'ejs')
- 使用
app.set()
配置默认模板页面的存放路径app.set('views', './views')
- 使用
res.render()
来渲染模板页面res.render('index.ejs', { 要渲染的数据对象 })
注意:模板页面的后缀名,可以省略不写!
const express = require('express')
const app = express()
// 1. 使用 app.set('view engine', '模板引擎的名称') 固定格式
app.set('view engine', 'ejs')
// 2. 设置模板页面的默认存放路径 app.set('views', '模板页面的具体存放路径')
app.set('views', './ejs_pages')
app.get('/', (req, res) => {
// 注意:如果想要调用 res.render 函数来渲染页面,必须先配置模板引擎
res.render('index.ejs', { name: 'cxk', age: 20, hobby: ['唱', '跳', 'rap','打篮球'] })
})
app.listen(3000, () => {
console.log('server running at http://127.0.0.1:3000')
})
使用art-template模板引擎
- 安装 两个包
cnpm i art-template express-art-template -S
- 自定义一个模板引擎
app.engine('自定义模板引擎的名称', 渲染函数)
- 将自定义的模板引擎,配置为 express 的默认模板引擎
app.set('view engine', '具体模板引擎的名称')
- 配置 模板页面得存放路径
app.set('views', '路径')
注意:配置模板引擎和文件后缀名要和自定义的模板引擎名称一致
const express = require('express')
const app = express()
// 1. 使用 app.engine() 方法自定义模板引擎
app.engine('html', require('express-art-template'))
// 2. 使用 app.set('view engine', '指定模板引擎名称') 来配置项目中用到的模板引擎
app.set('view engine', 'html')
// 3. 配置模板页面的存放路径
app.set('views', './art_page')
app.get('/', (req, res) => {
res.render('index.html', { name: 'cxk', age: 20, hobby: ['唱', '跳', 'rap','打篮球'] })
})
app.listen(3000, () => {
console.log('server running at http://127.0.0.1:3000')
})
6.1.7 路由 (router)
创建一个新的路由器对象。
var router = express.Router([options]);
- 什么是路由:路由就是对应关系;
- 什么叫做后端路由:前端请求的URL地址,都要对应一个后端的处理函数,那么 这种URL地址到 处理函数之间的对应关系,就叫做后端路由;
- 在Express中,路由的主要职责 就是 把请求分发到对应的处理函数中;
- 在Express中,如何 定义并使用路由呢?
// 1. 封装单独的 router.js 路由模块文件
const express = require('express')
// 创建路由对象
const router = express.Router()
router.get('/', (req, res)=>{})
router.get('/movie', (req, res)=>{})
router.get('/about', (req, res)=>{})
// 导出路由对象(暴露)
module.exports = router
6.1.8 中间件
定义:中间件就是一个处理函数,只不过这个函数比较特殊,包含了三个参数,分别是req,res,next
注意:中间件方法中的三个参数:
- req:请求对象;
- res:响应对象;
- next:next()可以被调用,表示调用下一个中间件方法;
6.1.9 Express 框架中对中间件的5种分类
- 应用级别的中间件: 挂载到 app 上的中间件
app.get('URL地址', (req, res, next)=> {})
; - 路由级别的中间件: 挂载到 router 对象上的中间件
router.get('url地址', (req, res, next)=>{})
- 错误级别的中间件: 回调函数中,有四个参数
app.use((err, req, res, next)=>{})
- 唯一内置的中间件:
express.static()
- 第三方中间件: 非express框架提供的,需要程序员手动安装才能使用的中间件;body-parser 解析post 表单数据
6.2 MySQL (CRUD)
配置数据库环境
// 1. 导入 mysql 模块
const mysql = require('mysql')
// 2. 创建mysql的连接对象
const conn = mysql.createConnection({
host: 'localhost',
user: 'root',
password: 'root',
database: 'mysql_001'
})
查询
const sqlStr1 = 'select * from users'
conn.query(sqlStr1, (err, result) => {
if (err) return console.log('获取数据失败!' + err.message)
console.log(result)
})
新增
const user = { uname: '小黄', age: 12, gender: '男' }
const sqlStr2 = 'insert into users set ?'
conn.query(sqlStr2, user, (err, result) => {
if (err) return console.log('插入数据失败!' + err.message)
console.log(result)
})
更改
const user = { id: 2, uname: '小绿', age: 22 }
const sqlStr3 = 'update users set ? where id=?'
// 注意:在 执行 conn.query 的时候,如果sql语句中,包含了 多个 ? 占位符,则,
// 第二个实参,必须传递一个数组,数组中的每一项,都要和 sql 语句中的 ? 对应上
conn.query(sqlStr3, [user, user.id], (err, result) => {
if (err) return console.log('修改数据失败!' + err.message)
console.log(result)
})
删除
const sqlStr4 = 'delete from users where id=?'
conn.query(sqlStr4, 2, (err, result) => {
if (err) return console.log('删除失败!' + err.message)
console.log(result)
})
提醒:熟练掌握SQL语句很重要,勤加练习
七. 模块加载机制
*附录 (资料网址,建议收藏)
- 模块化 – CommonJS规范
- Node.js – Node.js 核心API成员
- ES6 新增语法 – ECMAScript 6 入门
- Express第三方模块 – Express框架 API参考手册