目录
1. 什么是Node.js
2.Node.js可以做什么
3. 终端的一些快捷键
4. fs文件系统模块
5. path模块
6. http模块
7. 模块化
8. npm和包
9. 模块的加载机制
10. Express
1)express能做什么
2)express基本使用
3) 监听GET请求
4)监听POST请求
5)获取URL中携带的查询参数
6) 获取URL中的动态参数
7)托管静态资源
8)nodemon
9)express路由
10)express中间件
1)Node.js是一个基于Chrome V8引擎的JavaScript的后台运行环境
2)浏览器JavaScript的前端运行环境
3)Node.js无法调用DOM,BOM的API,Node.js有自己的内置API
1)基于Express框架,快速构建Web应用
2)基于Electron框架,构建跨平台的桌面应用
3)基于restify框架,快速构建API接口文档
4)读写和操作数据库、船舰使用的命令行工具辅助前端开发
向上箭头:快速定位到上一次执行的命令
tab:快速补全路径
esc:快速清空当前输入的命令
cls:清空终端
1)读取文件
//1. 导入fs模块
const fs=require('fs')
//2. 读取文件 参数:路径 读取文件编码格式 回调函数
fs.readFile('./poem.txt','utf8',function(err,data){
if(err){
return console.log('读取文件失败'+err.message);
}
console.log('读取文件成功'+data);
})
2) 写入文件
写入文件会覆盖之前文件中的内容
//3. 写入文件 参数: 文件的存放路径 写入的内容 回调函数
fs.writeFile('./poem.txt','你好哇,哈利波特',function(err,data){
console.log(err)
})
const path=require('path')
//路径拼接
const pathStr=path.join('/a','/b/c','../','./d')
console.log(pathStr)
//获取路径中的文件名
const fpath='a/b/c/d/test.html'
const fullname = path.basename(fpath)
console.log(fullname)
//把扩展名移除
const name = path.basename(fpath,'.html')
console.log(name)
//获取扩展名
const fext=path.extname(fpath)
console.log(fext)
1)客户端和服务器
客户端时负责消费资源的电脑;服务器是负责对外提供网络资源的电脑
2)核心思路
把文件的实际存放路径,作为每个资源的请求url地址
web服务器地作用
在浏览器访问网址,向服务器发送请求,服务器把发送的url当作读取文件的路径,向磁盘读取文件,读取完毕之后,响应给客户端,客户端收到的不是具体的文件,而是文件中的字符串
web服务器实例
const http=require('http')
const fs=require('fs')
const path=require('path')
const server=http.createServer()
server.on('request',(req,res)=>{
//1. 获取客户端请求的url地址
const url=req.url
console.log(url)
// //2. 把url映射为具体文件的存放路径
//预定义一个空白路径以存放路径
let fpath=''
if(url==='/'){
fpath=path.join(__dirname,'./honeywell/honeywell.html')
}else{
fpath=path.join(__dirname,'honeywell',url)
}
// const fpath=path.join(__dirname,url)
// //3. 根据映射的文件路径读取文件
fs.readFile(fpath,'utf8',(err,dataStr)=>{
//读取失败
if(err) return res.end('404 not found')
//防止中文显示乱码的问题
res.setHeader('Content-Type','text/html;charset=utf-8');
//读取成功
res.end(dataStr)
})
})
server.listen(8080,()=>{
console.log('server runing at http://127.0.0.1:8080')
})
1)模块化就是遵守固定的规则,把一个大文件拆分成独立且互相依赖的多个小模块
nodejs根据模块来源的不同,分为3大类
内置模块(fs,http,path等)
自定义模块(js文件)
第三方模块(第三方开放的模块)
2)模块作用域的好处
防止全局变量污染的问题
3)module对象
在一个自定义模块中,module.exports为空对象,当外界使用require()方法导入自定义模块时,得到的就是module.exports所指向的对象
Node.js遵循了ConmonJS模块化规范,ConmonJS规定了模块的特性以及各模块之间的依赖
1. module变量代表当前模块
2. module变量是一个对象,它的exports属性是对外的接口
3. 加载某个模块,是加载module.exports属性
1)包是第三方或团队开发出来的,可以免费使用
2)包是基于内置模块封装出来的,类似于jQuery是基于浏览器api封装出来的
3)使用包实现格式化时间实例
安装包
npm install moment
引入
const moment=require('moment')
使用
const newTime2=moment().format('YYYY-MM-DD HH:mm:ss')
4)包的语义化版本规范
第1位数字:大版本
第2位数字:功能版本
第3位数字:Bug修复版本
5)包管理配置文件
5.1 快速创建package.json这个包管理配置文件
npm init -y
5.2 注意:项目文件夹不能使用中文或者空格
使用npm install命令安装包的时候,npm包管理工具会自动把包的名称和版本号记录到package.json中
5.3 dependencies节点存放npm下载的包信息
5.4 一次性安装所有的包
npm install
5.5 卸载包
npm uninstall 包名称
5.6 devDependencies
如果某些包只在项目开发阶段会用到,可以放到devDependencies下,
如果某些包在项目开发阶段和上线之后都会用到,可以放到dependencies节点
npm i 包名 -D / npm i 包名 --save-dev
5.7 下包慢
因为npm下载的包是在国外的服务器上下的,所以速度慢
解决:使用淘宝npm镜像
镜像:一种文件存储形式,一个磁盘上的数据在另一个磁盘上存在一个完全相同的副本即镜像
切换npm下包的服务器地址
获取下包的地址:npm config get registry
切换下包地址:npm config set registry=https://registry.npm.taobao.org/
5.8 nrm
为了更方便的切换下包的镜像源
npm i nrm -g
查看所有可用的镜像源
nrm ls
将下包镜像切换为taobao
nrm use taobao
5.9 包的分类
a. 项目包
开发依赖包 (记录到devDependencies节点下)
核心依赖包 (记录到dependencies节点下)
b. 全局包
npm install的时候添加-g
c. i5ting_toc
可以把md文档转换为html页面
下载
npm install -g i5ting_toc
转换
i5ting_toc -f 转换的文件路径 -o
d. 规范的包结构
1)包必须以单独的目录存在
2)包的顶级目录下必须包含package.json 包管理配置文件
3) package.json中必须包含name、version、main,代表包的名字、版本号、包的入口
e. 开发属于自己的包
1)初始结构
index.js:初始文件
package.json:配置文件
README.md:阅读文档
2)package.json
{
"name":"huogewozi",
"version": "1.0.0",
"main":"index.js",
"description": "learn magic",
"keywords": ["gelanfenduo","silaitelin"],
"license": "ISC"
}
3)index.js
// 包的入口文件
function xuemofa(mofa){
if(mofa="飞来"){
return "飞来咒,使各种物品飞来。";
}else if(mofa="呼神护卫"){
return "守护神魔法,用于对付摄魂怪。";
}
}
//向外暴露需要的成员
module.exports={
xuemofa
}
4) 使用
const mofa=require('./mofa/index')
const resule=mofa.xuemofa('飞来')
console.log(resule)
5)index.js中定义转义html方法
为了防止用户输入html相关标签
//定义转义HTML字符的函数
function htmlEscape(htmlStr){
return htmlStr.replace(/<|>|"|&/g,(match)=>{
switch(match){
case '<':
return '<'
case '>':
return '≶'
case '"':
return '"'
case '&':
return '&'
}
})
}
还原为html方法
//定义还原HTML字符的函数
function htmlUnEscape(str){
return str.replace(/<|≶|"|&/g,(match)=>{
switch(match){
case '<':
return '<'
case '≶':
return '>'
case '"':
return '"'
case '&':
return '&'
}
})
}
6)发布包
6.1 注册用户
npm注册地址
npm | Sign Up
6.2 发布
改变服务器地址
nrm use npm
登录npm
把包发布到npm上
npm publish
删除已发布的包
npm unpublish 包名 --force (只能删除72小时内发布的包,删除24小时内不能重复发布)
1)模块优先从缓存中加载,在第一次加载后会被缓存。多次require同一模块只会执行一次
2)内置模块的优先级最高
3)加载自定义模块要使用'./'或者'../',否则会被当作内置模块或第三方模块
4)自定义加载流程:按文件名加载-> 加.js加载-> 加.json加载 -> 加.node加载 ->报错
5)第三方模块加载机制:当前目录 node_modules->上级目录node_modules->上上级目录node_modules6)目录作为模块:查找package.json文件中的main属性->若没有package.json或main入口不存在
或无法解析,加载目录下index.js->都没有报错
作用:与http一样,创建web服务器,Express是基于内置http封装出来的
Web网站服务器:专门对外提供Web网页资源的服务器
API接口服务器:专门对外提供API接口的服务器
安装 npm i [email protected]
//1. 引入express模块
const express=require('express')
//2. 创建web服务器
const app=express()
//监听客户端的get请求
app.get('/user',(req,resp)=>{
//调用express提供的res.send方法,向客户端响应一个JSON对象
resp.send({name:'小将',age:18})
})
app.post('/user',(req,resp)=>{
//调用express提供的res.send方法,向客户端响应一个文本字符串
resp.send('请求成功')
})
通过req.query可以获取客户端发送的查询参数
app.get('/',(req,resp)=>{
//获取客户端发送的查询参数,发送给客户端
console.log(req.query)
resp.send(req.query)
})
通过req.params获取通过:参数名的形式,匹配的动态参数值
app.get('/user/:id',(req,resp)=>{
//通过:参数名匹配动态参数,params是动态参数
console.log(req.params)
resp.send(req.params)
})
a.托管静态资源目录
使用express.static,可以非常方便地创建一个静态资源服务器
若托管多个静态资源文件,只需要调用多次express.static
express在制定的静态目录中查找文件,静态目录不会在路径中
const express=require('express')
const app=new express()
//调用express.static方法,快速对外提供静态资源,以下即可快速对外提供split以下的静态资源文件
app.use(express.static('./split'))
app.listen(8080,()=>{
console.log('express servr running at http://127.0.0.1')
})
b.挂载路径前缀,访问的时候需要加上前缀
//添加前缀
app.use('/abc',express.static('./split'))
自动识别代码改变,重启项目
a. 安装 npm i -g nodemon
express中,路由指的是客户端的请求与服务器处理函数之间的映射关系
1)路由的匹配过程
当一个请求到达服务器后,需要先经过路由的匹配,只有匹配成功,才会调用相应的处理函数
若请求类型和请求URL同时匹配成功,Express将会将这次请求交给对应的function函数进行处理
2)路由最简单的用法
const express=require('express')
const app=new express()
//挂载路由
app.get('/',(req,res)=>{
res.send('hihi')
})
app.post('/',(req,res)=>{
res.send('hello')
})
app.listen(8080,()=>{
console.log('http:127.0.0.1:8080/')
})
3) 模块化路由
a. 路由模块
//1. 导入express
const express=require('express')
//2. 创建express对象
const router=express.Router()
//3. 挂载具体路由
router.get('/user/list',(req,resp)=>{
resp.send('get something')
})
router.post('/user/add',(req,resp)=>{
resp.send('post something')
})
//4. 向外导出路由对象
module.exports=router
b. 注册路由模块
app.use()的作用,就是来注册全局中间件
const express=require('express')
const app=express()
//1. 导入路由模块
const router=require('./12.路由模块')
app.use(router)
app.listen(8080,()=>{
console.log('http:127.0.0.1:8080')
})
4)为路由模块添加前缀
app.use('api',router)
中间件,特指业务流程的中间处理环节
a. 中间件的调用流程
当一个请求到达xpress的服务器之后,可以连续调用多个中间件,从而对这次请求进行预处理
b.Express中间件的格式
本质上就是一个function处理函数,中间件函数的形参列表中,必须包含next参数,而路由处理函数只包含req和res
c. next函数的作用
next函数是实习多个中间件连续调用的关键,它表示把流转关系转交给下一个中间件或路由
d. 创建简单的中间件
const express=require('express')
const app=express()
//定义一个中间件函数
const mv=function(res,res,next){
//把流转关系,转交给下一个中间件或路由
next()
}
app.listen(8080,()=>{
console.log('http://127.0.0.1:8080')
})
e. 全局生效的中间件
客户端发起的任何请求,到达服务器后,都会触发的中间件,叫全局生效的中间件。
通过调用app.use,即可定义一个全局生效的中间件
//注册为全局生效的中间件
app.use(mw)
f. 中间件的简化形式
//简化形式
app.use((res,res,next)=>{
console.log('简单中间件')
//把流转关系,转交给下一个中间件或路由
next()
}
g. 中间件的作用
多个中间件之间,共享同一份req和res,可以在上游的中间件中,同一为req和res对象同一添加自定义的属性或方法,供下游的中间件或路由使用
h. 局部生效的中间件
不使用app.use定义的中间件,叫做局部生效的中间件
i. 中间件的分类
1)应用级别的中间件
通过app.use(),app.get(),app.post(),绑定到app实例上的中间件
2)路由级别的中间件
绑定到express.Router实例上的中间件
3)错误级别的中间件:专门用来捕获整个项目中发生的异常错误
错误级别中间件的function中,必须有4个形参,分别是(err,req,res,next)
const express=require('express')
const app=express()
app.get('/',(req,res)=>{
throw new Error('服务器内部发生了错误')
res.send('home page')
})
//定义错误级别的中间件,捕获整个项目的异常错误
app.use((err,req,res,next)=>{
console.log('发生一些错误'+err.message)
res.send(err.message)
})
app.listen(8080,()=>{
console.log('http:127.0.0.1:8080')
})
4) Express内置的中间件
express.static快速托管静态资源的内置中间件
express.json解析JSON格式的请求体数据(有兼容性,在4.16.0+版本中使用)
express.urlencoded解析URL-encoded格式的请求体数据(有兼容性,在4.16.0+版本中使用)
express.urlencoded是基于body-parser第三方中间件封装出来的
const express=require('express')
const app=express()
//配置解析表单的中间件 解析表单中的json格式的数据
app.use(express.json())
//通过express.urlencoded 来解析表单中的url-encoded格式的数据
app.use(express.urlencoded({extended:false}))
//通过express.urlencoded()中间件,来解析表单中的urlencoded格式的数据
app.get('/',(req,res)=>{
//req.body接收客户端发送过来的请求体数据
console.log(req.body)
res.send('home page')
})
app.listen(8080,()=>{
console.log('http:127.0.0.1:8080')
})
5)第三方中间件
由第三方开发出来的中间件
npm i body-parser
使用
const express=require('express')
const app=express()
//导入解析表单数据的中间件 body-parser
const parser=require('body-parser')
app.use(parser.urlencoded({extended: false}))
app.post('/user',(req,res)=>{
res.send('ok')
console.log(req.body)
})
app.listen(8080,function () {
console.log('express server runing at http://127.0.0.1')
})
j. 自定义中间件
1)监听req的data事件和rea的end事件
在中间件中,需要监听req对象的data事件,来获取客户端发送到服务端的数据
若数据较大,客户端会把数据切割后,分批发送到服务器,所以data事件可能会触发多次。每次触发都会获取到完整数据的一部分
const express=require('express')
const app=express()
//解析表单数据的中间件
app.use((req,res,next)=>{
//1 定义一个str字符串,用来存储客户端发送的请求体数据
let str=''
//2 监听req的data事件
req.on('data',(chunk)=>{
str+=chunk
})
//3 监听req的end事件
req.on('end',()=>{
console.log(str)
})
})
app.post('/user',(req,res)=>{
res.end('ok')
})
app.listen(8080,function () {
console.log('http://127.0.0.1:8080')
})
k. querystring模块解析请求体数据
用来处理查询字符串,通过这个模块的parse函数,可以轻松地查询字符串,解析成对象的格式
const express=require('express')
const app=express()
//导入node.js内置的querystring模块
const qs=require('querystring')
//解析表单数据的中间件
app.use((req,res,next)=>{
//1 定义一个str字符串,用来存储客户端发送的请求体数据
let str=''
//2 监听req的data事件
req.on('data',(chunk)=>{
str+=chunk
})
//3 监听req的end事件
req.on('end',()=>{
console.log(str)
const body=qs.parse(str)
console.log(body)
})
})
app.post('/user',(req,res)=>{
res.end('ok')
})
app.listen(8080,function () {
console.log('http://127.0.0.1:8080')
})
l.将解析出来的数据对象挂载为req.body
上游的中间件和下游的中间件及路由之间,共享一份req和res。因此,可以将解析出来的数据,挂载在req的自定义属性,命名为req.body,供下游使用
//3 监听req的end事件
req.on('end',()=>{
console.log(str)
const body=qs.parse(str)
//将数据挂载到req.body上 通过req.body可以重新拿到数据
req.body=body
next()
})
m.将自定义中间件封装成模块
//导入node.js内置的querystring模块
const qs=require('querystring')
const customBodyParser=(req,res,next)=>{
//1 定义一个str字符串,用来存储客户端发送的请求体数据
let str=''
//2 监听req的data事件
req.on('data',(chunk)=>{
str+=chunk
})
//3 监听req的end事件
req.on('end',()=>{
console.log(str)
const body=qs.parse(str)
//将数据挂载到req.body上 通过req.body可以重新拿到数据
req.body=body
next()
})
}
module.exports=customBodyParser
引入模块
const express=require('express')
const app=express()
//导入自己封装的中间件模块
const customBodyParser=require('./13.custom-body-parser')
app.use(customBodyParser)
app.post('/user',(req,res)=>{
// res.end('ok')
res.send(req.body)
})
app.listen(8080,function () {
console.log('http://127.0.0.1:8080')
})