Node.js
一、node.js
node.js是一个基于Javascript这门语言开发出来的技术,本文我就来为大家介绍一下Node.js学习的一些基础内容。如有错误的地方欢迎大家指出错误之处。在我们了解这些基础之后,可以使用node实现一些数据库连接操作,自己写一些前后端小项目。
node运行
在我们安装node并且编写一个js文件之后,我们便可以开始运行我们的node项目了:
node 文件名.js
二、系统模块
2.1 系统模块
Node运行环境提供的API. 因为这些API都是以模块化的方式进行开发的, 所以我们又称Node运行环境提供的API为系统模块
2.2 fs文件系统模块
2.2.1读取、写入文件操作
// 在我们使用node的文件系统模块之前我们需要使用require来导入该模块
const fs = require("fs");
// 读取文件模块
// 同步读取:调用fs.requireFileSync(参数1,参数2)
// 参数1:读取文件的路径
// 参数2:读取文件时候所按照的编码格式,一般默认指定utf8
//该方法不接受回调函数,函数直接返回结果
var data = fs.readFileSync('sample.txt', 'utf-8');
console.log(data);
// 异步读取:调用fs.readFile(参数1[,参数2],参数3)方法读取文件
/*
参数1:读取文件的路径
参数2:读取文件时候所按照的编码格式,一般默认指定utf8
参数3:回调函数,拿到读取失败和成功的结果 err dataStr
*/
fs.readFile('../files/1s.txt','utf8',(err,dataStr)=>{
// 打印失败的结果
// 如果读取成功返回null
// 读取失败返回一个错误对象,dataStr 的值为undefined
console.log(err);
console.log('=====');
// 打印成功的结果
console.log(dataStr);
if(err){
return console.warn('读取文件失败!'+ err.message);
}
console.log(dataStr);
})
// 写入文件模块
// 调用writeFile(参数1,参数2[,参数3],参数4)函数为文件写入内容
// 参数1:写入文件存放的路径(如果写入的文件不存在,则系统会自动地生成相对应的文件)
// 参数2:表示写入的内容
// 参数3: 回调函数
fs.writeFile('../files/1.txt','这是一段写入的内容',(err)=>{
// 如果文件写入与成功,则err为null
// 如果写入失败,则err等于一个错误对象
console.log(err);
})
2.3 http系统模块
我们可以使用node内置模块的http模块,来创建一个web服务器,可以进行一些简单的前后端交互操作。使用http模块的基本的步骤如下:
// 创建基本的web服务器
// 1.导入http模块
const http = require('http');
// 2.创建web服务器实例
const serve = http.createServer()
//3.绑定处request事件
// serve.on('request',处理函数(req,res))
/*
当客服端请求服务端时,就会调用serve.on()函数为服务器的request事件绑定处理函数
req:是请求的对象,包含了与客户端相关的数据和属性:如:
req.url :客户端请求的URL地址,但是只会获取地址后面的后缀,如:http://127.0.0.1/user,这是req.url只会获取到 /user
req.method :客户端的method请求类型
res :响应对象,包含与服务端相关的数据和属性,如:
res.end()方法的作用:向客户端发送指定的内容,并且结束这次请求的处理过程
res.setHeader() 设置响应头:(设置该响应头是为了防止中文乱码)
'Content-type':'text/html;charset=utf-8
*/
serve.on('request',(req,res)=>{
console.log('开始请求web服务');
})
// 4.启动服务器
// serve.listen('端口',callback)
// 我们可以自己设置响应的端口号,如:8080、8088等等。当我们使用80作为我们服务器的端口号的时候,我们在访问的时候,不需要加端口号,浏览器会默认的认为是80端口访问
serve.listen(80,()=>{
console.log('http://l27.0.0.1');
})
一个简单的案例
响应不同的请求地址
const http = require('http');
const server = http.createServer();
server.on('request',(req,res)=>{
let content = '404 NOt Found';
if(req.url === '/' || req.url === '/index.html'){
content = '<h1>index.html</h1>'
}
if(req.url === '/about.html'){
content= '<h1>About.html</h1>'
}
res.setHeader('Content-type','text/html; utf-8;')
res.end(content);
})
server.listen(8080,()=>{
console.log('Your server at http://127.0.0.1:8080');
})
2.3 path路径模块
path 模块是Node.js官方提供的、用来处理路径的模块。它提供了一系列的方法和属性,用来满足用户对路径的处理需求。
在我们平时遇到路径拼接的操作时,都会选择使用字符串拼接的方法,但是使用这种方法的弊端有很多,如:有时候会由于我们的一些失误,导致路径出现错误的情况,而且在如果我们要将文件移植的时候,会导致移植性差。这个时候我们就可以使用path模块,来对路径做一些修改和拼接。
今后凡是涉及到路径拼接的操作,都要使用path.join()方法进行处理。不要直接使用+ 进行字符串拼接。
// path.join([...path])方法,用来将多个路径片段拼接成一个完整的路径字符串
/*
paths<string>路径片段的序列
返回值<string>
*/
// path.basename(path[,ext])方法,用来从路径字符串中,将文件解析出来
/* path <string> 必选参数,表示一个路径的字符串
ext <string> 可选参数,表示文件扩展名
返回:<string> 表示路径中的最后一部分
*/
// path.extname(path)的语法格式
/*
path <string> 必选参数,表示一个路径的字符串
返回:<string> 返回得到的扩展名字符串
*/
// 引入path模块,在之后涉及到路径拼接的时候,记得使用path.join的方法,不会出现什么问题
// 拼接路径
// path.join([..arg])
const path = require('path');
// 在拼接路径的时候,只有../能回退目录
const url = path.join('/a','/b','../');
// __dirname会返回当前文件所在的目录的路径
const url2= path.join(__dirname)
console.log(url,url2);
const fpath = '/a/v/c/index.html';
console.log(path.extname(fpath)); //html
const fapth = __dirname + '/index.html';
const fullName = path.basename(fapth,'.html');
console.log(fullName); // index
三、require
/*
require:用来导入相关的模块
1.内置模块 2.用户自定义模块 3.第三方模块 (也可以叫做 包 ,是依赖于内置模块封装出来的)
其中只有用户自定义模块引入时,需要添加路径
在使用require引入模块时,会自动执行模块中的代码
存在模块作用域
在一个模块中的,如果需要导出数据的话,需使用module.exports方法,且导出的对象以最后的module.export指向的对象为准
在模块里面,exports和module.exports所指向的对象相同 export === module.exports => true
切记:使用require()导入模块时,得到的永远是module.exports指向的对象,并非exports
避免在同一个模块中同时使用exports 和 module.exports
我们在使用require导入时,如果不添加文件的后缀名,则系统会自动的按照 js json node 的顺序逐层的向上寻找去寻找,如果都没有找到,则会报错
*/
const m1 = require('./test')
console.log(m1);
// test.js
console.log(module);
module.exports = {
name: '小明',
age: 20
}
module.exports = {
name: 20
}
module.exports.wife = 30;
四、Express框架
1.1nodemon
// nodemon: 在编写Node.js项目时,如果修改项目代码,就需要频繁的重启,很繁琐,使用nodemon就可以很好的解决这个问题,它会自动的重启项目,方便我们开发和调试
// 安装nodemon : npm i -g nodemon
//执行: nodemon 执行文件路径
2.1 Express
Express 是一个基于
Node
平台的Web应用开发框架,它提供了一系列的强大特性,帮助你创建各种Web应用。
express安装: npm i express
2.2 Express 框架特性
-
提供了
简洁的路由定义
方式 -
对获取 http
请求参数
进行了
简化处理
-
对
模板引擎支持程度高
,方便渲染动态HTML页面 -
拥有
中间件
机制有效
控制 HTTP 请求
-
拥有大量第三方中间件对功能进行扩展
2.3 express初体验
// 导入express
const express = require('express');
// 创建web服务器
const app = express();
// 编写post请求方法
app.post('/post',(req,res)=>{
res.send("POST")
})
// 编写get请求方法
app.get('/', (req, res) => {
res.send("GET");
})
// 启动服务器
app.listen(80,()=>{
console.log('http://127.0.0.1');
})
3.中间件
3.1 是什么中间件
中间件:业务处理流程中的处理函数
中间件是一堆方法,可以接收客户端发来的请求、可以对请求作出响应,也可以将请求继续交给下一个中间件进行处理
/*
中间件:业务处理流程中的处理函数
全局生效的中间件:任何一个客户端请求,到达服务端都会触发的中间件。叫做全局中间件
通过调用app.use(中间函数),即可定义一个全局生效的中间件
局部生效的中间件:不使用app.use()定义的中间件,都叫做局部中间件
中间件作用:多个中间件之间共享的是同一份req和res.所以我们可以在上游的中间件中,统一
为req和res对象添加自定义属性或方法,供下游的中间件或路由进行使用
定义多个全局中间件:可以使用app.use()连续定义多个中间件,系统会按照定义的顺序
进行执行
中间件使用注意事项:
1.一定要将中间件放置在路由之前
2.客户端发送的请求,可以连续调用多个中间件
3.不要忘记在中间件函数里面写next()函数
4.为了防止代码逻辑混乱,调用next()函数后不要写额外的代码
5.连续调用多个中间件,多个中间件之间,共享req 和 res对象
中间件的分类:
1.应用级别:绑定到app实例上的中间件,如app.use()、app.get()
2.路由级别:绑定到路由上的中间件
3.错误级别:专门用来捕获整个项目中发生的异常错误,从而防止项目异常崩溃的问题
app.use(function(err,req,res,next){
console.log('发生错误' + err.message);
res.send('Error! + err.message)
})
特殊:必须注册在所有路由之后
4.Express内置:express.static :没有兼容性
express.json 解析JSON格式(有兼容性,仅在4.16.0+版本中使用)
express.urlencoded 解析URL-encoded格式的请求数据(有兼容性,仅在4.16.0+版本中使用)
5.第三方
*/
// 定义一个简单的中间件函数
const express = require('express');
const app = express();
const mw = function(req,res,next){
const time = Date.now();
req.startTime = time;
console.log('一个简单的中间件函数');
next()
}
const mw2 = function(req,res,next){
const time = Date.now();
req.startTime = time;
console.log('一个简单的中间件函数');
next()
}
//全局中间件
// app.use(mw)
// 局部生效的中间件(同时使用多个局部中间件,或者使用数组将中间件包起来,然后调用)
app.get('/',mw,mw2,(req,res)=>{
res.send('Index.html' + (Date.now() - req.startTime))
})
app.post('/user',(req,res)=>{
res.send('没中间件')
})
app.get('/error',(req,res)=>{
throw new Error('服务器内部发生错误!!')
})
// 错误级别中间件,捕获整个项目的异常错误,从而防止程序崩溃
app.use(function(err,req,res,next){
res.send('服务器错误' + err.message)
})
app.listen(80,()=>{
console.log('https://127.0.0.1');
})
3.2 中间件的应用
1.路由保护:
客户端在访问需要登录的页面时,可以先使用中间件判断用户登录状态,用户如果未登录,则拦截请求,直接响应,禁止用户进入需要登录的页面
// 引入 express 框架
const express = require('express')
// 创建Web服务器
const app = express();
// 为客户端访问 /user 请求时候的中间件
app.use('/user', (req, res, next) => {
// 用户没有登录
let isLogin = false;
// 如果用户登录
if (isLogin) {
console.log("用户已经登录")
// 让请求继续向下执行
next();
} else {
console.log("用户未登录")
// 如果用户没有登录,直接对客户端作出响应
res.send('您还没有登录,无法访问当前页面');
}
})
app.get('/user', (req, res) => {
res.send('您已登录 可以访问当前页面')
})
app.get("/admin",(req,res)=>{
res.send("不受中间件约束")
})
// 监听端口
app.listen(3000);
console.log('网站服务器启动成功');
2.网站维护公告
在所有路由最上面定义接收所有请求的中间件,直接为客户端做出响应,网站正在维护中。
// 引入 express 框架
const express = require('express')
// 创建Web服务器
const app = express();
// 此处不设置next()函数,阻止用户访问网站
app.use((req, res, next) => {
res.send('当前网站正在维护...');
})
// 将不会被访问
app.get('/user', (req, res) => {
res.send('您已登录 可以访问当前页面')
})
// 监听端口
app.listen(80,()=>{
console.log('http://127.0.0.1')
});
3.自定义404页面
// 引入 express 框架
const express = require('express')
// 创建Web服务器
const app = express();
app.use((req, res, next) => {
// 为客户端响应404状态码以及提示信息
res.status(404).send('当前访问的页面是不存在的');
})
// 监听端口
app.listen(80,()=>{
console.log("http://127.0.0.1")
});
重点:
// 使用res.send()方法向客户端发送数据
// 使用req.query属性,可以访问到客户端通过查询字符串的形式,发送到服务器的参数
// 使用req.params对象,可以访问到URL中,通过:匹配到的动态参数
/* 使用req的data事件,来获取客户端发送到服务器的数据:如果客户端返回的数据比较多的话,客户端会将数据分割成好几部分,则data事件会触发多次,
没触发一次就会获取一些数据,我们需要对这些数据进行拼接
req的end事件:当客户端所有的数据发送完毕之后,会触发end事件
4.express路由
4.1路由
// 路由:就是一种映射关系
/*
路由的组成:三部分 请求类型、请求地址、处理函数
app.METHOD(PATH,HANDLER)
路由匹配过程:每当一个请求到达服务器之后,需要先经过路由的匹配,只有匹配成功之后,才调用对应的处理函数
注意:按照定义的先后顺序进行匹配;请求类型和请求的URL同时匹配成功,才会调用对应的处理函数
使用:
1.简单的使用:(缺点随着路由的增多,代码量会增加)
引入调用:const express = require(express)
const app = express();
挂载路由:
app.get(地址,(req,res)=>{})
启动服务器:
app.listen(启动端口,()=>{})
2.模块化路由(推荐使用)
创建路由模块对应的.js文件
调用express.Router()函数创建路由对象
想路由对象上挂载具体的路由
使用module.exports向外共享路由
使用app.use()函数注册路由模块
*/
// express路由.js
const express = require('express');
const router = express.Router();
router.get('/',(req,res)=>{
res.send('GET');
})
router.post('/',(req,res)=>{
res.send('POST')
})
module.exports = router
// router.js
const express = require('express');
const app = express();
const router = require('./express路由')
// app.use()是用来注册全局中间件的
app.use(router)
app.listen(80,()=>{
console.log('http://127.0.0.1');
})
4.2 GET请求参数的获取
Express 框架中使用
req.query
即可
获取GET参数
,框架内部会将GET参数转换为
对象
并返回。
// 引入 express 框架
const express = require('express');
// 创建Web服务器
const app = express();
app.get('/index', (req, res) => {
// req.query 获取请求参数
res.send(req.query)
})
// 监听端口
app.listen(80,()=>{
console.log('http://127.0.0.1')
});
4.3POST参数
Express 中接收
POST请求参数
POST请求参数
在服务器,可以使用req.body这个属性来获取客户端发送过来的请求体数据
,默认情况下,
如果不配置解析表单的中间件,则req.body 默认等于 undefined
方法一:需要借助第三方包
body-parser
安装body-parser: npm i body-parser
body-parser文档地址:http://www.expressjs.com.cn/en/resources/middleware/body-parser.html
// 引入 express 框架
const express = require('express');
// 创建Web服务器
const app = express();
const bodyParser = require("body-parser")
//配置body-parser
//只要加入这个配置,则在req请求对象上多出来一个属性:body;
//也就是说你就可以直接通过req.body来获取表单POST请求体数据了;
// 拦截所有请求
// extended: false 方法内部使用 querystring 模块处理请求参数的格式
// extended: true 方法内部使用第三方模块 qs 来处理请求参数的格式
app.use(bodyParser.urlencoded({extended: false}));
app.post('/index', (req, res) => {
// req.query 获取请求参数
res.send(req.body)
})
// 监听端口
app.listen(80,()=>{
console.log('http://127.0.0.1')
});
方法二:
// 配置解析表单数据的中间件
app.use(express.urlencoded({extended:false})) // 解析application/x-www-form-urlencoded格式的表单数据
app.use(express.json()) // 解析json格式的表单数据