什么是系统模块
Node运行环境提供的**API**. 因为这些**API**都是以模块化的方式进行开发的, 所以我们又称Node运行环境提供的API为系统模块
系统模块fs 文件操作(f:file 文件 ,s:system 系统,文件操作系统 )获取系统模块fs
1.获取系统fs模块
const fs = require('fs');
2.通过模块内部的readFile读取文件内容
//fs.readFile(文件路径,文件编码,callback(err.doc))
fs.readFile('./01.helloworld.js', 'utf8', (err, doc) => {
// 如果文件读取出错err 是一个对象 包含错误信息
// 如果文件读取正确 err是 null
// doc 是文件读取的结果
console.log(err);
console.log(doc);
});
3.通过模块内部的writeFile写入内容
fs.writeFile('./demo.txt', '即将要写入的内容', err => {
if (err != null) {
console.log(err);
return;
}
console.log('文件内容写入成功');
})
系统模块path 路径操作
1.路径拼接语法
path.join('路径1','路径2',...)
//1.导入path模块
const path = require('path');
//2.路径拼接
let finialPath = path.join('itcast', 'a', 'b', 'c.css');
// 输出结果 itcast\a\b\c.css
console.log(finialPath);
相对路径VS绝对路径
- 大多数情况下使用绝对路径,因为相对路径有时候相对的是命令行工具的当前工作目录
- 在读取文件或者设置文件路径时都会选择绝对路径
- 使用__dirname获取当前文件所在的绝对路径
系统模块HTTP
创建web服务器(★★★)
//引用系统模块
const http = require('http');
//创建web服务器
const app = http.createServer();
//当客户端发送请求的时候(监听客户端发送过来的请求)
app.on('request', (req, res) => {
// 响应
res.end('<h1>hi, user</h1>');
});
// 监听3000端口
app.listen(3000);
console.log('服务器已启动,监听3000端口,请访问 localhost:3000')
系统模块-url
const url = require('url');
专门用来处理请求路径相关
第二个参数(可省):如果设为 true,则返回的 URL 对象的 query 属性会是一个使用 querystring 模块的 parse() 生成的对象。 如果设为 false,则 query 会是一个未解析未解码的字符串。 默认为 false。
第三个参数(可省):如果设为 true,则 // 之后至下一个 / 之前的字符串会解析作为 host。 例如, //foo/bar 会解析为 {host: 'foo', pathname: '/bar'} 而不是 {pathname: '//foo/bar'}。 默认为 false
url.parse(urlString,boolean,boolean)
//parse这个方法可以将一个url的字符串解析并返回一个url的对象
url.parse(req.url)
url.format(urlObj)
format这个方法是将传入的url对象编程一个url字符串并返回
url.format({
protocol:"http:",
host:"182.163.0:60",
port:"60"
});
/*
返回值:
'http://182.163.0:60'
*/
url.resolve(from, to)
resolve这个方法返回一个格式为"from/to"的字符串,把参数进行一个拼接,然后返回
const url = require('url');
url.resolve('/one/two/three', 'four'); // '/one/two/four'
url.resolve('http://example.com/', '/one'); // 'http://example.com/one'
url.resolve('http://example.com/one', '/two'); // 'http://example.com/two'
系统模块-querystring
一般是对http请求所带的数据进行解析(post)
const querystring = require('querystring');
querystring.parser(服务端接受的参数)
querystring.parse(str,separator,eq,options)
parse这个方法是将一个字符串反序列化为一个对象。
str:指需要反序列化的字符串;
separator(可省):指用于分割str这个字符串的字符或字符串,默认值为"&";
eq(可省):指用于划分键和值的字符或字符串,默认值为"=";
decodeURIComponent:传入一个function,用于对含有%的字符串进行解码,默认值为querystring.unescape,默认是utf-8的编码,如果不是需要进行定义
// 假设 gbkDecodeURIComponent 函数已存在。
querystring.parse('w=%D6%D0%CE%C4&foo=bar', null, null,
{ decodeURIComponent: gbkDecodeURIComponent });
querystring.stringify(obj,separator,eq,options)
stringify这个方法是将一个对象序列化成一个字符串,与querystring.parse相对。
obj:指需要序列化的对象
separator(可省):用于连接键值对的字符或字符串,默认值为"&";
eq(可省):用于连接键和值的字符或字符串,默认值为"=";
options(可省):传入一个对象,该对象可设置encodeURIComponent这个属性:
encodeURIComponent:值的类型为function,可以将一个不安全的url字符串转换成百分比的形式,默认值为querystring.escape()。
querystring.stringify({name: 'heima', sex: [ 'man', 'women' ] });
/*
return:
'name=heima&sex=man&sex=women'
*/
querystring.escape(str)
escape可使传入的字符串进行编码
querystring.escape("name=程序员");
/*
return:
'name%3D%E9%BB%91%E9%A9%AC%E7%A8%8B%E5%BA%8F%E5%91%98'
*/
querystring.unescape(str)
unescape方法可将含有%的字符串进行解码
querystring.unescape('name%3D%E9%BB%91%E9%A9%AC%E7%A8%8B%E5%BA%8F%E5%91%98');
/*
return:
'name=程序员'
*/
第三方模块
别人写好的、具有特定功能的、我们能直接使用的模块即第三方模块,由于第三方模块通常都是由多个文件组成并且被放置在一个文件夹中,所以又名包 。
第三方模块有两种存在形式
1.以js文件的形式存在,提供实现项目具体功能的API接口
2.以命令行工具形式存在,辅助项目开发
使用命令行进行第三方模块的下载和删除
使用 npm 命令:npm (node package manager) : node的第三方模块管理工具
-
下载:npm install 模块名称
-
卸载:npm unintall package 模块名称
第三方模块- nodemon 模块
nodemon是一个命令行工具,用以辅助项目开发。在Node.js中,每次修改文件都要在命令行工具中重新执行该文件,非常繁琐,nodemon可以监听文件的修改,只要修改保存了,就会重新执行一次
使用步骤
-
使用npm install nodemon –g 下载它
-
在命令行工具中用nodemon命令替代node命令执行文件
第三方模块- nrm 模块
nrm ( npm registry manager ):npm下载地址切换工具;
npm默认的下载地址在国外,国内下载速度慢
使用步骤
-
使用npm install nrm –g 下载它
-
查询可用下载地址列表 nrm ls
-
切换npm下载地址 nrm use 下载地址名称
第三方模块- Gulp模块
基于node平台开发的前端构建工具,将机械化操作编写成任务, 想要执行机械化操作时执行一个命令行命令任务就能自动执行了,用机器代替手工,提高开发效率。
Gulp能做什么
-
项目上线,HTML、CSS、JS文件压缩合并
-
语法转换(es6、less ...)
-
公共文件抽离
-
修改文件浏览器自动刷新
Gulp使用
-
使用npm install gulp下载gulp库文件
-
在项目根目录下建立gulpfile.js文件
-
重构项目的文件夹结构 src目录放置源代码文件 dist目录放置构建后文件
-
在gulpfile.js文件中编写任务.
-
在命令行工具中执行gulp任务
简单入门:
1.创建一个文件夹
2.创建gulpfile.js 文件
3.下载Gulp模块
4.把项目源代码放入到当前文件夹中
5.创建一个文件夹,放处理好的文件
6.在gulpfile.js里面编写代码
const gulp = require('gulp');
const htmlmin = require('gulp-htmlmin');
const fileinclude = require('gulp-file-include');
const less = require('gulp-less');
const cssm = require('gulp-csso');
const babel = require('gulp-babel');
const uglify = require('gulp-uglify');
//创建任务htmlmin
gulp.task('htmlmin', done => {
//获取目标文件
gulp.src('./src/*.html')
//抽取公共代码,在被抽取的html文件中抽取的代码位置@@include('公共文件路径')
.pipe(fileinclude())
//压缩操作
.pipe(htmlmin({ collapseWhitespace: true }))
//输出处理后的文件
.pipe(gulp.dest('dist'));
done();
});
gulp.task('cssmin', done => {
gulp.src(['./src/css/*.less', './src/css/*.css'])
.pipe(less())
.pipe(cssm())
.pipe(gulp.dest('dist/css'));
done();
});
gulp.task('jsmin', done => {
gulp.src('./src/js/*.js')
.pipe(babel({ presets: ['@babel/env'] }))
.pipe(uglify())
.pipe(gulp.dest('dist/js'));
done();
});
gulp.task('copy', done => {
gulp.src('./src/images/*')
.pipe(gulp.dest('dist/images'));
done();
});
//构建任务列表,只要执行default任务会自动执行列表中的所有任务
gulp.task('default', gulp.series('htmlmin', 'cssmin', 'jsmin', 'copy', done => {
done();
}));
Gulp插件
-
gulp-htmlmin :html文件压缩 npm install gulp-htmlmin
-
gulp-csso :压缩css npm install gulp-csso
-
gulp-babel :JavaScript语法转化 npm install gulp-babel @babel/core @babel/preset-env
-
gulp-less: less语法转化 npm install gulp-less
-
gulp-uglify :压缩混淆JavaScript npm install gulp-uglify
-
gulp-file-include 公共文件包含 npm install gulp-file-include
-
browsersync 浏览器实时同步
package.json文件的作用
项目描述文件,记录了当前项目信息,例如项目名称、版本、作者、github地址、当前项目依赖了哪些第三方模块等。
使用npm init -y命令生成。
{
"name": "description", //项目名称
"version": "1.0.0", //版本号
"description": "", //项目描述
"main": "index.js", //项目主入口
"scripts": { //命名的别名
"test": "echo \"Error: no test specified\" && exit 1",
"build": "nodemon app.js" //取了别名后,只需要输入命令 npm run build
},
"keywords": [],//关键字
"author": "", //作者
"license": "ISC",//项目遵循协议 ISC 是开放源代码协议
"dependencies": {//项目依赖
"formidable": "^1.2.1",
"mime": "^2.3.1"
},
"devDependencies": {//开发依赖
"gulp": "^3.9.1"
}
}
项目依赖
-
在项目的开发阶段和线上运营阶段,都需要依赖的第三方包,称为项目依赖
-
使用npm install 包名命令下载的文件会默认被添加到 package.json 文件的 dependencies 字段中
开发依赖
-
在项目的开发阶段需要依赖,线上运营阶段不需要依赖的第三方包,称为开发依赖
-
使用npm install 包名 --save-dev命令将包添加到package.json文件的devDependencies字段中
这样区分开来的话,方便与我们在不同环境下下载相应的插件,例如,我们项目打包上线的时候,就不需要开发依赖,我们就可以通过命令 npm install --production 来下载项目依赖包
package-lock.json文件的作用
-
锁定包的版本,确保再次下载时不会因为包版本不同而产生问题
-
加快下载速度,因为该文件中已经记录了项目所依赖第三方包的树状结构和包的下载地址,重新安装时只需下载即可,不需要做额外的工作
Node.js中模块加载机制(★★★)
模块查找规则-当模块拥有路径但没有后缀时
require('./find.js');
require('./find');
-
require方法根据模块路径查找模块,如果是完整路径,直接引入模块。
-
如果模块后缀省略,先当前目录下的同名JS文件再找同名JS文件夹
-
如果没有找到同名文件夹就会去package.json文件中查找main选项中的入口文件
-
如果入口文件不存在或者没有指定入口文件找文件夹中的index.js
-
如果都没有就会报错
模块查找规则-当模块没有路径且没有后缀时
require('find');
-
Node.js会假设它是系统模块
-
Node.js会去node_modules文件夹中
-
首先看是否有该名字的JS文件
-
再看是否有该名字的文件夹
-
如果是文件夹看里面是否有index.js
-
如果没有index.js查看该文件夹中的package.json中的main选项确定模块入口文件
-
否则找不到报错
第三方模块-dateformat
日期格式处理模块
npm install dateformat
var dateFormat = require('dateformat');
var now = new Date();
// Basic usage
dateFormat(now, "dddd, mmmm dS, yyyy, h:MM:ss TT");
第三方模块-router
实现路由
npm install router
//引入路由模块,返回的是一个方法
const getRouter = require('router');
//调用方法,返回路由对象
const router = getRouter();
router.get('/index', (req, res) => {
res.end('index请求成功');
});
router.get('/list', (req, res) => {
res.end('list请求成功');
});
//在我们监听的请求函数里面开启路由功能
//监听服务
server.on('request', (err, doc) => {
//启用路由功能第三个参数回调函数必须带上
router(req, res, () => {
//路由分发完毕后,再调用此函数
});
});
第三方模块-serve-static
引入静态资源
npm install serve-static
//1.引入静态资源加载的模块
const serveStatic = require('serve-static');
//2.得到静态资源加载对象 传递静态资源的路径,方便后续使用
const static = serveStatic(path.join(__dirname, 'public'));
server.on('request', (req, res) => {
...
//3.开启静态资源
static(req, res, () => {});
});
第三方模块-Express
Express框架简介
- 提供了方便简洁的路由定义方式
- 对获取HTTP请求参数进行了简化处理
- 对模板引擎支持程度高,方便渲染动态HTML页面
- 提供了中间件机制,有效控制HTTP请求
- 拥有大量第三方中间件对功能拓展
下载Express第三方模块
npm install express
第三方模块-body-parser
npm install body-parser
下载第三方库
//引入第三方库
const express = require('express');
//引入body-parser模块 Express框架默认使用body-parser作为请求体解析中间件
const bodyParser = require('body-parser');
//创建web服务器
const app = express();
//bodyParser,urlencoded 会检测里面是否有请求参数,如果有请求参数会帮我们进行解析,然后添加一个req.body属性,把值赋值给body属性,在请求中调用了next方法,把请求控制权交给了下个路由
app.use(bodyParser.urlencoded({ extended: false }));//urlencoded返回值刚好是一个函数
app.post('/add', (req, res) => {
//通过req.body属性来获取post请求参数
res.send(req.body);
});
//监听端口
app.listen(8080);
第三方模块-art-template
下载
npm install art-template
//导入模板引擎,返回的是一个方法
const template = require('art-template');
//返回的是拼接好的字符串
const html = template('模板路径',插入模板中的数据(对象类型));
第三方模块-bcrypt
密码加密
bcrypt 依赖的其他环境
-
python 2.x
-
node-gyp;npm install -g node-gyp
-
windows-build-tools;npm install --global --production windows-build-tools
安装完依赖环境后需要将python的安装目录配置到环境变量中,然后重新启动命令行工具,使用npm install bcrypt 下载模块
// 导入bcrypt
const bcrypt = require('bcrypt');
async function run () {
// 生成随机字符串
// genSalt方法接收一个数值作为参数
// 数值越大 生成的随机字符串复杂度越高
// 数值越小 生成的随机字符串复杂度越低
// 默认值是 10
// 返回生成的随机字符串
const salt = await bcrypt.genSalt(10);
// 对密码进行加密
// 1. 要进行加密的明文
// 2. 随机字符串
// 返回值是加密后的密码
const result = await bcrypt.hash('123456', salt);
console.log(salt);
console.log(result);
}
run();
//数据库中的密码进行了加密后不能直接用用户输入的密码与数据库的密码比对,需要把用户传递过来的密码进行加密,然后再和数据库中的比对
// true 比对成功
// false 对比失败
await bcrypt.compare(‘明文密码’, ‘加密密码’)
第三方模块-express-session
npm install express-session
cookie与session
cookie:浏览器在电脑硬盘中开辟的一块空间,主要供服务器端存储数据。
-
cookie中的数据是以域名的形式进行区分的。
-
cookie中的数据是有过期时间的,超过时间数据会被浏览器自动删除。
-
cookie中的数据会随着请求被自动发送到服务器端。
session:实际上就是一个对象,存储在服务器端的内存中,在session对象中也可以存储多条数据,每一条数据都有一个sessionid做为唯一标识
//导入express-session模块
const session = require('express-session');
//配置session模块
app.use(session({
secret: 'secret key',
//saveUninitialized: false 用到session时才会去初始化
//saveUninitialized: true 不管用不用到session都会初始化
saveUninitialized: false,
cookie: {
maxAge: 24 * 60 * 60 * 1000
}
}));
if (isValid) {
//登录成功时将用户名存储到req.session对象中
req.session.username = user.username;
res.redirect('/admin/user');
} else {
res.status(400).render('admin/error', { msg: '邮件地址或者密码错误' });
}
admin.get('/loginOut', (req, res) => {
//退出时删除session
req.session.destroy(function() {
//清楚cookie
res.clearCookie('connect.sid');
res.redirect('/admin/login');
});
});
第三方模块-Joi
JavaScript对象的规则描述语言和验证器
安装 npm install joi
const Joi = require('joi');
const schema = {
username: Joi.string().alphanum().min(3).max(30).required().error(new Error(‘自定义错误信息’)),
password: Joi.string().regex(/^[a-zA-Z0-9]{3,30}$/),
access_token: [Joi.string(), Joi.number()],
birthyear: Joi.number().integer().min(1900).max(2013),
email: Joi.string().email()
};
//验证对象是否符合规则
Joi.validate({ username: 'abc', birthyear: 1994 }, schema);
定义项目中的表单验证
// 引入joi模块
const Joi = require('joi');
// 定义对象的验证规则
const schema = {
username: Joi.string().min(2).max(5).required().error(new Error('username属性没有通过验证')),
birth: Joi.number().min(1900).max(2020).error(new Error('birth没有通过验证'))
};
async function run () {
try {
// 实施验证
await Joi.validate({username: 'ab', birth: 1800}, schema);
}catch (ex) {
console.log(ex.message);
return;
}
console.log('验证通过')
}
run();
第三方模块-formidable
作用:解析表单,支持get请求参数,post请求参数、文件上传
安装: npm install formidable
demo
// 引入formidable模块
const formidable = require('formidable');
// 创建表单解析对象
const form = new formidable.IncomingForm();
// 设置文件上传路径
form.uploadDir = "/my/dir";
// 是否保留表单上传文件的扩展名
form.keepExtensions = false;
// 对表单进行解析
form.parse(req, (err, fields, files) => {
// fields 存储普通请求参数
// files 存储上传的文件信息
});
<!--
enctype 指定表单数据的编码类型
默认是application/x-www-form-urlencoded
传输的数据类型是 name=zhangsan&age=20
multipart/form-data 将表单数据编码成二进制类型
-->
<!-- /分类标题 -->
<form class="form-container" action="/admin/article-add" method="post"
enctype="multipart/form-data">
// 引入formidable第三方模块
const formidable = require('formidable');
const path = require('path');
const { Article } = require('../../model/article')
module.exports = (req, res) => {
// 1.创建表单解析对象
const form = new formidable.IncomingForm();
// 2.配置上传文件的存放位置
form.uploadDir = path.join(__dirname, '../', '../', 'public', 'uploads');
// 3.保留上传文件的后缀
form.keepExtensions = true;
// 4.解析表单
form.parse(req, async (err, fields, files) => {
// 1.err错误对象 如果表单解析失败 err里面存储错误信息 如果表单解析成功 err将会是null
// 2.fields 对象类型 保存普通表单数据
// 3.files 对象类型 保存了和上传文件相关的数据
res.send(files.cover.path.split('public')[1])
})
// res.send('ok');
}
上传图片实时预览功能
//创建文件读取对象
let reader = new FileReader();
//读取文件,this.files是上传时选择的文件列表
reader.readAsDataURL(this.files[0]);
//readAsDataURL不会直接返回结果,需要监听onload事件
reader.onload = function(){
preview.src = reader.result;
}