Node.js
使用javascript借助node.js可以做后端开发
node.js是一个基于chrom V8引擎的javascript运行环境
- js代码在浏览器运行可以做前端开发
- js代码在node.js运行可以做后端开发
- node.js是一个基于chrom V8引擎的javascript运行环境
- node.js 中无法调用Dom和Bom等浏览器内置API
1.node.js的适用
- 基于express框架,快速构建web应用
- 基于Electron框架,构建跨平台的桌面应用
- 基于restify框架,快速构建API接口项目
- 读写和操作数据库
终端
计算机实现人机交互的方法,利用终端可以知道所安装node的版本号
windows+R输入cmd打开终端,输入node -v
总结终端的部分快捷命令:
1.终端将命令行从C盘转换为D盘:
D:
2.同一盘下文件路径转换:
cd+空格+Path
3.运行js代码:
node+path
4.快速定位到文件所处路径:
在文件所处目录按住shift右键打开powershell窗口
2.fs文件系统模块
由node.js官方提供用来操作文件的模块
导入fs模块:
const fs=require('fs')//导入fs模块
fs.readFile():
读取指定文件中的内容
示例代码:
const fs=require('fs')
//参数1:读取文件的存放路径
//参数2:读取文件时候采用的编码格式,一般默认utf8
//参数3:回调函数,拿到读取失败和成功的结果err和dataStr
fs.readFile('./1.txt','utf8',function(err,dataStr) {
console.log(err);//读取成功,输出err为null
console.log(dataStr);//输出读取的数据,若读取失败的话,输出为undefined
})
fs.writeFile():
向指定文件中写入内容
const fs=require('fs')
fs.writeFile('./1.txt','hello js',function(err) {
console.log(err);//写入成功,输出err为空
})
- 可以根据err是否为null判断读取/写入成功还是失败
处理路径问题:
提供完整存放路径,可以解决路径拼接问题,但是移植性较差,不利于维护,使用__dirname更好。
path路径模块
导入path
const path=require('path')
1.path.join代码示例
const pathStr=path.join('/a','/b/c','../../','./d','e')//\a\b\d\e||../表示消除前一层路径
实际使用
fs.readFile(path.join(__dirname,'需要拼接的路径'))
2.path.basename():获取路径中的文件名
const path=require('path')
const fpath='/a/b/c/index.html'
const fullname=path.basename(fpath)
console.log(fullname)//输出index.html
也可以获取删除扩展名后的文件名
const path=require('path')
const fpath='/a/b/c/index.html'
const nameWithoutExt=path.basename(fpath,'path')
console.log(nameWithoutExt)//输出index
获取路径中的文件扩展名
- path.extname()
const path=require('path')
const fpath='/a/b/c/index.html'
const fext=path.extname(fpath);
console.log(fext)//输出.html
3.http模块
1.关于客户端和服务器:
网络节点中,负责消费资源的电脑,叫做客户端;负责对外提供网络资源的电脑,叫做服务器。
Http模块是用来创建web服务器的模块。通过其提供的http.createServer()
把普通的电脑编程web服务器
导入http(创建web服务器):
const http=require('http');
2.进一步理解Http模块的作用
安装服务器软件(例如IIS,Apache),把普通的电脑变成一台Web服务器
3.服务器相关概念
1.IP地址
特殊ip地址:127.0.0.1 这个地址可以把电脑既作为服务器又作为客户端
2.域名
3.端口号
每个服务对应一个端口号
4.创建最基本的web服务器
基本步骤:
- 导入http模块
const http=require('http');
- 创建web服务器实例
const server=http.creatServer();
- 为服务器实例绑定request 事件
server.on('request',(req,res)=> {
console.log('someone visit our web server.')
})
- 启动服务器
server.listen(80,()=> {
console.log('http server running at http://127.0.0.1')
})
const http=require('http');
const server =http.createServer();
server.on('request',function(req,res){
console.log('Someone visit our web server');
})
server.listen(80,function(){
console.log('server running at http://127.0.0.1:80');
})
- req请求对象
服务器接收到客户端的请求,调用通过server.on()为服务器绑定的Request事件处理函数。
如果想在事件处理函数中,访问与客户端相关的数据或属性,见下
server.on('request',(req)=>{
const url=req.url//获取请求的url地址
const method=req.method//
const str=`Your request url is ${url},and request method is ${method}`
console.log(str);
})
- 解决中文乱码问题
res.setHeader('Content-Type','text/html;CHARSET=UTF-8')
5.根据不同的url响应不同的Html内容
实现步骤:
- 获取请求的url地址
- 设置默认响应内容为404NOT FOUND
- 判断用户请求的是否为/或/index.html 首页
- 判断用户请求的是否为/about.html关于页面
- 设置Content-Type 响应头,防止中文乱码
- 使用res.end()把内容响应给客户端
const http=require('http');
const server =http.createServer();
server.on('request',(req,res) =>{
const url=req.url;
let content='<h1>404 Not found</h1>'
if(url=='/'||url==='/index.html') {
content='<h1>首页</h1>'
} else if(url==='/about.html') {
content='<h1>关于页面</h1>'
}
res.setHeader('Content-Type','text/html; charset=utf-8')
res.end(content)
console.log(1);
})
server.listen(80,function(){
console.log('server running at http://127.0.0.1:80');
})
4.模块化
把大文件拆分成独立化并相互依赖的小文件
模块化规范
1.根据模块来源:
- 内置模块
- 自定义模块
- 第三方模块:
2.加载模块
加载内置模块
const fs=require('fs')
加载用户的自定义模块
const custom=require('./custom.js')//可以省略.js后缀名
加载第三方模块
const moment=require('moment')
当使用require时,加载其他模块会执行加载的其他模块的代码
3.模块作用域
防止了全局变量污染的问题
4.向外共享模块作域中的成员
- module对象(存储了和当前模块有关的属性)
- module.exports对象(将模块中的成员共享出去)
5.向外共享成员方法
module.exports.username='zs'
const age=20
module.exports.sayHello=function() {
console.log('Hello!');
}
module.exports.age=age
6.注意点
- 使用require方法导入模块时,导入的结果是,永远以module.exports指向的对象为准:如下->打印的为新对象
module.exports.username='zs'
module.exports.sayHello=function() {
console.log('Hello!');
}
//让module.exports指向一个新的对象
module.exports= {
nickname:'小黑',
sayHi() {
console.log('Hi!');
}
}
7.exports 对象
默认情况,exports和module.exports指向同一个对象
8.exports和module.exports的使用误区
-
不建议一个模块同时使用
-
使用requir()导入模块时,得到的永远是module.exports指向的对象:
实例:
const username='zs'
exports.username=username
module.exports= {
gender:'男',
age:22
}
console.log(exports);//uesrname
console.log(module.exports);//gender,age
const username='zs'
exports.username=username
console.log(exports);//username
console.log(module.exports);//username
module.exports=exports
9.CommonJS中的模块化规范
-
module代表当前模块、
-
module.exports时对外接口
-
require()方法用于加载模块
3.npm与包
->3.1 包
包:node.js中的第三方模块又叫包,由第三方个人或团队开发出来的,免费使用,基于内置模块封装出来的,提供了更高级,更方便的API
搜索包(网站):https://www.npmjs.com/
下载包(服务器):https://registry.npmjs.org/
下载包管理工具:
1.npm体验
- 传统格式化时间做法
function dateFormat(dtStr) {
const dt=new Date(dtStr)
const y=dt.getFullYear()
const m=padZero(dt.getMonth()+1)
const d=padZero(dt.getDate())
const hh=padZero(dt.getHours())
const mm=padZero(dt.getMinutes())
const ss=padZero(dt.getSeconds())
return `${y}-${m}-${d} ${hh}:${mm}:${ss}`
}
//补0
function padZero(n){
return n>9?n:'0'+n
}
module.exports= {
dateFormat
}
const Time=require('./time')
const dt=new Date()
Time.dateFormat(dt)
const newDT=Time.dateFormat(dt)
console.log(newDT);
在项目中安装包的命令
npm i
- 格式化时间高级做法(包的用法需要自行查阅)
const moment=require('moment')
const dt=moment().format('YYYY-MM-DD HH:mm:ss')
console.log(dt);
2.
安装指定版本的包
npm i moment@2.22.2
2.包管理配置文件
package.json包管理配置文件
如何记录项目中安装了那些包:
项目根目录中,创建一个叫做package.json的配置文件,记录安装了哪些包,方便剔除node_modules目录之后,在团队成员之间共享的源代码
注意:今后在项目开发中,一定要把node_modules文件夹,添加到.gitignore忽略文件中
快速创建package.json:npm init -y
解决下包速度慢的问题
切换npm的下包镜像源
//查看当前下包的镜像源
npm config get registry
//切换至淘宝镜像
npm config set registry=http://registry.npm.taobao.org/
//检查是否下载成功
npm config get registry
使用nrm小工具切换镜像源更方便
//通过 npm 包管理器,将nrm包装为全局可用的工具
npm i nrm -g
//查看所有可用的镜像源
nrm ls
//将下包的镜像源切换为taobao镜像
nrm us taobao
Express
- 基于node.js的快速,开放,极简的Web开发框架
- 与Http模块类似,专门用来创建Web服务器
- 使用Express可以快速创建Web网站的服务器或API接口的服务器
express使用
1.安装
项目所处目录中,运行
npm i express@4.17.1
2.创建基本的Web服务器
//1.导入express
const express=require('express')
//2.创建web服务器
const app=express()
//3.启动web服务器
app.listen(80,()=> {
console.log('express server running at http:/127.0.0.1')
})
监听客户端GET请求
app.get('请求url',function(req,res)){}
监听客户端POST请求
app.post('请求url',function(req,res))
把内容响应给客户端
res.send()
3.托管静态资源
3.1. 单个静态资源
express提供了一个非常好用的函数,叫做express.static(),通过它,我们可以非常方便的创建一个静态资源服务器,例如通过以下代码将 public目录下的图片,CSS文件,JavaScript文件对外开放访问了:
app.use(express.static('public'))
代码中的使用方法:
const express=require('express')
const app=express()
//在这里,调用express.static()方法,快速对外提供静态资源
app.use(express.static('./clock'))//此段代码将clock目录下的文件对外开放
app.listen(80,()=> {
console.log('express server running at http://127.0.0.1');
})
集成终端启动node.js后,浏览器输入http://127.0.0.1/index.html
即可打开clock下的index.html文件。
注意:访问路径中没有存放index.html的目录名clock
所以express.static中的文件夹的名称肯定不会出现在访问路径中。
3.2. 托管多个静态资源目录
多次调用express.static()函数
app.use(express.static('public'))
app.use(express.static('files'))
- 访问静态资源文件时
例如
const express=require('express')
const app=express()
//在这里,调用express.static()方法,快速对外提供静态资源
app.use(express.static('./clock'))//1
app.use(express.static('./files'))//2
app.listen(80,()=> {
console.log('express server running at http://127.0.0.1');
})
访问http://127.0.0.1/index.html,得到clock目录下的index.html文件
若把1和2 两个句子调换顺次序,则的到files目录下的index.html文件
3.3. 挂载路径前缀
如果希望在托管的静态资源访问路径之前,挂载路径前缀,使用如下方式:
app.use('public',express.static('public'))
代码示例:
const express=require('express')
const app=express()
//在这里,调用express.static()方法,快速对外提供静态资源
app.use('/abc',express.static('./files'))
app.use(express.static('./clock'))
两个文件目录中都含有index.html文件,此时若访问http://127.0.0.1/index.html,得到的是clock目录下的文件,因为访问files下的文件需要前缀/abc
4.nodemon
编写调试项目代码时,如果修改了项目的代码,则需要手动close掉,再重新启动,非常繁琐。使用nodemon可以监听项目文件的变动,代码被修改后,会自动帮我们重启项目
4.1安装nodemon
终端运行如下命令
npm i -g nodemon
4.2.使用nodemon
将node命令替换为nodemon命令,使用nodemon app.js来启动项目
express路由
- 路由是客户端的请求与服务器处理函数之间的映射关系
- express中的路由由三部分组成,分别是请求的类型
请求的url地址,处理函数,格式如下
app.method(path,handler)
路由的匹配过程:请求到达服务器后,先经过路由的匹配,只有匹配成功,才会调用对应的处理函数。匹配时,按照路由顺序进行匹配
express中使用路由最简单的用法, 就是把路由挂载到app上
const express=require('express')
//创建web服务器,命名为app
const app=express()
//挂载路由
app.get('/',(req,res)=> {
res.send('hello world')
})
app.post('/',(req,res)=> {
res.send('post request')
})
//启动web服务器
app.listen(80,()=> {
console.log('http://127.0.0.1')
})
- 这种方法不建议
模块化路由
方便对路由进行模块化管理,将路由抽离为单独的模块
创建一个路由模块
//1.导入express
const express=require('express')
//2.创建路由对象
const router=express.Router()
//3.挂载具体路由
router.get('/user/list',(req,res)=> {
res.send('Get user list')
})
router.post('/user/add',(req,res)=> {
res.send('Add new user')
})
//4.向外导出路由对象
module.exports=router
注册路由模块
//1.导入路由模块
const router=require('./03.router')
//2.注册路由模块
app.use(router)
//注意:app.use()函数的作用,就是来注册全局中间件
为路由模块添加统一的访问前缀
//1.导入路由模块
const userRouter=require('./router/user.js')
//2.注册路由模块,添加统一的访问前缀/api
app.use('/api',useRouter)
中间件
express中间件的格式,本质上就是一个function函数
定义中间件函数
const express=require('express')
const app=express()
//定义一个最简单的中间件函数
const mw=function(req,res,next) {
console.log('这是一个最简单的中间件函数');
//把流转关系,转交个下一个中间件或路由
next();
}
app.listen(80,()=> {
console.log('http://127.0.0.1');
})
全局生效的中间件:
客户端发起的任何请求,到达服务器之后,都会触发中间件,叫做全局生效的中间件,app.use()
//定义一个最简单的中间件函数
const mw=function(req,res,next) {
console.log('hgwfuy');
//把流转关系,转交个下一个中间件或路由
next();
}
//全局生效的中间件
app.use(mw)
定义全局生效的中间件简化形式
app.use(function(req,res,next){
console.log('dsger')
next()
})
中间件的作用
多个中间件,共享一份req和res.基于这样的特性,我们可以在上游的中间件中,统一为req或res对象添加自定义的属性或方法,供下游的中间件或路由进行使用
定义多个全局中间件
局部生效的中间件
不使用app.use定义的中间件
示例:
const mw1=function(req,res,next){
console.log('这是中间件函数')
next()
}
//mw1这个中间件只在“当前路由中生效”,这种用法属于“局部生效的中间件”
app.get('/',mw1,function(req,res){
res.send('Home page')
})
//mw1不会影响下面这个路由
app.get('/user',function(req,res){
res.send('Users page')
})
定义多个局部中间件
app.get('/',mw1,mw2,(req,res)=>{res.send('Home page')})
app.get('/',[mw1,mw2],(req,res)=>{res.send('Home page')})
两种写法对等
中间件的注意事项
- 路由之前注册中间件
- 客户端发送过来的请求
- 调用完next()后,不要再写额外的代码
如果没有配置任何解析表达数据的中间件,则req.body默认等于undefined
感谢阅读!