Node 学习
1、fs文件模块
fs.readFile()方法,用来读取指定文件中的内容
fs.readFile(path[,option],callback)
参数1:必选参数,表示文件路径
参数2:可选参数,表示声明编码格式来读取文件
参数3:必选参数,文件读取完成后,通过回调函数拿到读取的结果
例子
const fs = require('fs')
fs.readFile('./1.txt','utf8',function(err,dataStr){
console.log(err)
console.log('------------')
console.log(dataStr)
})
fs.writeFile()方法,用来读取指定文件中的内容
const fs = require('fs')
fs.writeFile('./2.txt','abcd',function(err){
console.log(err)
})
小红=23 小红:23
//将成绩的数组,按照空格进行分割
const arrOld = dataStr.split('')
//循环分割后的数组,对每一项数据,进行字符串的替换操作
const arrNew = []
arrOld.forEach(item => {
arrNew.push(item.replace('=',':'))
})
//把新数组中的每一项,进行合并换行,得到一个新的字符串
const newStr = arrNew.join('\r\n')
- 路径动态拼接
__dirname表示当前文件所处的目录
const fs = require('fs')
fs.readFile(__dirname+'/files/1.txt','utf8',function(err,dataStr){
console.log(err)
console.log('------------')
console.log(dataStr)
})
2、path路径模块
-
path.join()方法,用来将多个路径片段拼接成一个完整的路径字符串const path = require('path') const pathStr = path.join('/a','/b/c','../','./d','e') console.log(pathStr) //输出\a\b\d\e ..\会抵消前一个路径 fs.readFile(path.join(__dirname,'/files/1.txt'),'utf8',function(err,dataStr){ }) -
path.basename()方法,用来从路径字符串中,将文件名解析出来
const path = require('path')
//定义文件的存放路径
const fpath = '/a/b/c/index.html'
const fullName = path.basename(fpath)
console.log(fullName) //index.html
const fullName = path.basename(fpath,'html')
console.log(fullName) //index
path.extname()获取文件扩展名
const path = require('path')
//定义文件的存放路径
const fpath = '/a/b/c/index.html'
const fext = path.extname(path)
console.log(fext) //.html
3、综合案例
const fs = require('fs')
const path = require('path')
//匹配<style></style>标签的正则表达式
// \s表示空白字符串 \S表示非空白字符 *表示匹配任意次
const regStyle = /<style>[\s\S]*<\/style>
const regScript = /<script>[\s\S]*<\/script>
//读取需要被处理的HTML文件
fs.readFile(path.join(__dirname,'./index.hrml'),'utf8',(err,dataStr) = >{
if(err){
return console.log('读取文件失败'+err.message)
}
resolveCSS(dataStr)
resolveJS(dataStr)
resolveHTML(dataStr)
})
//定义处理css样式的方法
function resolveCSS(htmlStr){
//使用正则提取需要的内容
const r1 = regStyle.exec(htmlStr)
//将提取出来的样式字符串,进行字符串的replace操作
const newCSS = r1[0].replace('<style>','').replace('</style>','')
//调用fs.writeFile()方法,将提取的样式,写入到clock目录中 index.css 的文件里面
fs.writeFile(path.join(__dirname,'./clock/index.css'),newCSS,function(err){
if(err)return console.log('写入样式失败'+err.message)
console.log('成功')
})
}
4、http模块
//导入http模块
const http = require('http')
//创建web服务器实例
const server = http.createServer()
//为服务器实例,绑定request事件,监听客户端的请求
//req是请求对象,它包含了与客户端相关的数据和属性
//req.url 是客户端请求的URL地址
//req.methods是客户端的method请求类型
server.on('request',function(req,res){
console.log('somone visit our web server')
})
//请求服务器
server.listen(8080,function(){
console.log('server running at http://127.0.0.1:8080')
})
解决中文乱码问题
res.setHeader('Content-Type','text/html;charset=utf-8')
5、模块化
5.1 模块化好处
模块化:是指解决一个复杂问题时,自顶逐层的把系统划分成若干模块的过程,对于整个系统来说,模块时可组合、分解和更换的单元。
复用性,可维护性,按需加载方便调用
5.2模块化规范
5.3 Node中的模块化
- 内置模块
- 自定义模块
- 第三方模块
1、加载模块
const fs = require('fs')
2、模块作用域
只能在当前模块被访问。防止全局变量污染问题
3、向外共享模块作用域中的成员
module对象
module.exports ={
name:'zf',
}
4、模块化规范。CommonJS模块化规范。
- 每个模块内部,module变量代表当前模块 。
- module 变量是一个对象,它的exports 属性(module.exports)是对外的接口。
- 加载某个模块,其实是加载该模块的module.exports属性。require()方法用于加载模块。
5.4 npm 与 包
6、Expres
1.创建基本的Web服务器
const express = require('express')
const app = express()
app.listen(80,()=>{
console.log('服务器已经启动!')
})
2、监听GET,POST请求
app.get('请求URL',(req,res)=>{
})
app.post('请求URL',(req,res)=>{
})
3、把内容响应给客户端 res.send(),可以把处理好的内容,发送给客户端。
app.get('/user',(req,res)=>{
//向客户端发送 JSON 对象
res.send({name:'zs',age:20})
})
app.post('/user',(req,res)=>{
//向客户端发送 JSON 对象
res.send({name:'zs',age:20})
})
4、获取URL中携带的查询参数
通过req.query对象,可以访问到客户端通过查询字符串的形式,发送到服务器的参数。
app.get('/user'()=>{
//req.query默认是一个空对象
//客户端使用 ?name=zs&age=20 这种查询字符串形式,发送到服务器的参数
//可以通过 req.query 对象访问到
//req.query.name req.query.age
console.log(req.query)
})
5、获取URL的动态参数
req.params对象 **: **匹配到的动态参数
app.get('/user/:id',()=>{
console.log(req.params)
res.send(req.params)
})
请求127.0.0.1/user/1
打印 {id:'1'}
6.1 express.static()快速 对外提供静态资源
app.use(express.static('./public'))
挂载路径前缀
app.use('public',express.static('./public'))
6.2 nodemon
npm i -g nodemon
nodemon app.js 代码保存后,会自动更新服务器
6.3 路由
客户端的请求与服务器处理函数之间的映射关系
app.METHOD(PATH,HANDLER)
请求类型 请求的URL地址 处理函数
6.4 路由模块
-
创建路由模块对应的 .js 文件
-
调用 express.Router() 函数创建路由
-
向路由对象上挂载具体的路由
-
使用 module.exports 向外共享路由对象
-
使用 app.use() 函数注册路由模块
var express = require('express') //导入express
var router = express.Router() //创建路由对象
router.get('/user/list',(req,res)=>{ //挂载获取用户列表的路由
res.send('得到用户列表')
})
router.post('/user/add',(req,res)=>{ //挂载添加用户的路由
res.send('添加新用户')
})
modules.exports = router //向外导出路由对象
使用 导入
const router = require('./router')
app.use('/api',router)
6.5 中间件
//中间件函数
app.get('/',(req,res,next) => {
next()
})
全局生效中间件
app.use((req,res,next)=>{
console.log('简单中间件')
next()
})
中间件作用,共享一份req,res
app.use((req,res,next) => {
//获取到请求到达服务器的时间
const time = Date.now()
//为req对象,挂载自定义属性,从而把时间共享给后面的所有路由
req.startTime = time
next()
})
局部生效的中间件
const mw1 = (req,res,next) => {
console.log('这是中间件函数')
next()
}
//mw1 这个中间件只在当前路由中生效,这种用法属于局部生效的中间件
app.get('/',mw1,(req,res) => {
res.send('home page')
})
//mw1 这个中间件不会影响下面这个路由
app.get('/user',(req,res) => {
res.send('user page')
})
- 路由之前注册中间件
- 客户端发送过来的请求,可以连续调用多个中间件进行处理
- 执行完中间件的业务代码之后,不要忘记调用next()函数
- 为了防止代码逻辑混乱,调用next()函数后不要写额外的代码
- 连续调用,多个中间件时,多个中间件,共享req,res对象
6.6 中间件的分类
1、应用级别的中间件
通过app.use() 或 app.get() 或 app.post() ,绑定到app实例上面的中间件,叫做应用级别的中间件。
2、路由级别的中间件
绑定 express.Router() 实例上面的中间件,叫做路由级别的中间件。
var router = express.Router()
3、错误级别的中间件
专门捕获整个项目中发生的异常错误,防止项目异常崩溃。错误级别中间件必须注册在所有路由之后
app.get('/',(req,res)=>{ //1.路由
throw new Error('服务器内部发生错误')//2.抛出一个自定义的错误
res.send('home page')
})
app.use((err,req,res,next)=>{//3.错误级别的中间件
console.log('发生了错误:'+ err.message)//4.在服务器打印错误消息
res.send('Error!'+ err.message)//5.向客户端响应错误相关的内容
})
4、内置中间件 4.16.0版本+
- expres.static:快速托管静态资源的内置中间件
- express.json:解析JSON格式的请求数据----兼容性
- express.urlencodeed:解析URL-encoded格式的请求体数据----兼容性
app.use(express.json())
//req.body 来获取 JSON 格式的表单数据和url-encoded格式的数据
app.use(express.urlencodeed({extended:false}))
5、第三方的中间件
6.7 自定义中间件
在中间件中,需要监听req对象的data事件,来获取客户端发送到服务器的数据
数据量大,则客户端会把数据切割后,分批发送到服务器。
所以data事件可能会触发多次,每一次触发data事件,获取到数据只是完整数据的一部分,需要手动对接收到的数据进行拼接。
const express = require('express')
const app = express()
const qs = require('querystring')
app.use((req,res,next) => {
let str = '' //定义一个字符串,专门存储客户端发送过来的请求体数据
req.on('data',(chunk) => { //每次触发data都会把,数据存储在str中。
//拼接请求体数据
str += chunk
})
req.end('end',()=>{ //监听end事件,结束后打印全部数据
//把字符串格式的请求体数据,解析成对象格式。
const body = qs.parse(str)
req.body = body
//console.log(body)
next()
})
})
app.post('/user',(req,res)=>{
res.end('req.body')
})
将自定义中间件封装为模块------创建一个 .js文件
const qs = require('querystring')
const bodyParser = (req,res,next) => {
let str = '' //定义一个字符串,专门存储客户端发送过来的请求体数据
req.on('data',(chunk) => { //每次触发data都会把,数据存储在str中。
//拼接请求体数据
str += chunk
})
req.end('end',()=>{ //监听end事件,结束后打印全部数据
//把字符串格式的请求体数据,解析成对象格式。
const body = qs.parse(str)
req.body = body
//console.log(body)
next()
})
}
module.exports = bodyParser
//使用:导入自己封装的中间件函数,注册为全局可用的中间件
cosnt customBodyParser = require(./xx.js)
app.use(customBodyParser)
6.8 使用Express写接口 GET-POST
1、创建app.js文件
const express = require('express')
const app =express()
//导入路由模块
const router = require('./apiRouter')
//把路由模块,注册到app上
app.use('/api',router)
app.listen(80,()=>{
console.log('服务器已经启动')
})
2、创建API路由模块-----apiRouter.js
const express = require('express')
const router = express.Router
//挂载路由处
router.get('/get',(req,res) => {
//通过req.query获取客户端通过查询字符串,发送到服务器的数据
const query = req.query
//调用res.send方法,向客户端响应处理的结果
res.send({
status:0,//0表示处理成功 ,1表示处理失败
msg:'GET请求成功', .//状态描述
data:query //响应给客户端的数据
})
})
router.post('/post',(req,res) => {
//通过req.body获取客户端通过请求体,发送到服务器的URL-encoded数据,配置中间app.use(express.urlencoded({extended:fasle}))
const body = req.body
//调用res.send方法,向客户端响应处理的结果
res.send({
status:0,//0表示处理成功 ,1表示处理失败
msg:'POST请求成功', .//状态描述
data:body //响应给客户端的数据
})
})
module.exports = router
1、跨域问题---cors
npm i coarsconst cors = require('cors')- 在路由前调用
app.use(cors())
<html>
<head>
<script>
</script>
</head>
<body>
<button id="btnGET">
GET
</button>
<button id="btnPOST">
POST
</button>
<script>
$(function () {
$('#btnGET').on('click',function (){
$ajax({
type:'GET',
url:"http://127.0.0.1/api/get",
data:{name:'zd',age:20},
sucess: function (res) {
console.log(res)
}
})
})
})
$(function () {
$('#btnPOST').on('click',function (){
$ajax({
type:'POST',
url:"http://127.0.0.1/api/post",
data:{bookname:'谁属中国哑巴',age:23},
sucess: function (res) {
console.log(res)
}
})
})
})
</script>
</body>
</html>
- Access-Control-Allow-Origin字段的值为通配符*,表示允许来自任何域的请求。
res.setHeader('Access-Control-Allow-Origin','*')
- Access-Control-Allow-Headers,只支持客户端向服务器发送九个请求头
``````res.setHeader('Access-Control-Allow-Headers','Content-Type,X-Custom-Header')```
- Access-Control-Allow-Methods,如果希望通过PUT,DELETE等方式请求服务器的资源,则需要在服务器端,通过这个来指明实际请求所允许使用的HTTP方法
``````res.setHeader('Access-Control-Allow-Methods','*')```
7、数据库
| id | username | password | status |
|---|---|---|---|
| 1 | 张三 | 123456 | 0 |
| 2 | 李四 | 341125 | 1 |
| 3 | 托尼史塔克 | 7758258 | 1 |
1、查
select 列名 from 表名
select * from users /*查所有*/
select id from users
2、增
insert into 表名 (列1,列2,列3) values (值1,值2,值3)
insert into users (username,password) values ('托尼史塔克','20202020')
3、改
update 表名称 set 列名称 = 新值 where 列名称 = 某值 where更新的条件
update users set username='美国队长' where id=1
update users set username='雷神',password='7758258' where id=2
4、删
delete from 表名称 where 列名称 = 值
delete from users where id=3
5、where子句:限定选择的标准
select * from users where id>1
6、and 和 or 运算符 相当于 || 和 &&
select * from users where id>1 and status=1
7、order by 语句,更具指定的列,进行排序,默认升序排序,asc关键字代表升序排序
升序排序:select * from users order by status asc
降序排序:select * from users order by id desc
多重排序:select * from users order by status desc, username asc
8、count(*)函数,总数据条数
```select count(*) from users where status=1``
返回值 count=2
9、使用as为列设置别名
select count(*) as total from users where staus=1
8、使用 mysql
//安装 npm imysql
//导入
const mysql = require('mysql')
cosnt db = mysql.createPool({
host:'127.0.0.1',
user:'root',
password:'admin2022!',
database:'test'
})
module.exports = db
1、查询数据
const str1 = 'select * from users'
//查询表中数据
db.query(str1,(err,results) => {
if(err) return console.log(err.message)
console.log(results)
})
2、插入数据
//要插入到users表中的数据对象
const user = {username:'Doctor Strange',password:'123456'}
//待执行的SQL语句,其中英文的 ? 表示占位符
const sqlStr = 'insert into users (username,password) values (?,?)'
//使用数组的形式,依次为 ? 占位符指定的具体的值
db.query(sqlStr,[user.username,user.password],(err,results) => {
if(err) return console.log(err.message)
if(result.affectedRows ===1){ //判断数据是否插入成功
console.log('插入数据成功')
}
})
快速插入
//要插入到users表中的数据对象
const user = {username:'Doctor Strange',password:'123456'}
//待执行的SQL语句,其中英文的 ? 表示占位符
const sqlStr = 'insert into users set ?'
//使用数组的形式,依次为 ? 占位符指定的具体的值
db.query(sqlStr,user,(err,results) => {
if(err) return console.log(err.message)
if(result.affectedRows ===1){ //判断数据是否插入成功
console.log('插入数据成功')
}
})
3、更新数据
const user = {id:4,username:'Doctor Strange',password:'123456'}
const sqlStr = 'update users set username=?,password=? where id=?'
db.query(sqlStr,[user.username,user.password,user.id],(err,results) => {
if(err) return console.log(err.message)
if(result.affectedRows ===1){ //判断数据是否插入成功
console.log('更新数据成功')
}
})
便捷方式
const user = {id:4,username:'Doctor Strange',password:'123456'}
const sqlStr = 'update users set ? where id=?'
db.query(sqlStr,[user,user.id],(err,results) => {
if(err) return console.log(err.message)
if(result.affectedRows ===1){ //判断数据是否插入成功
console.log('更新数据成功')
}
})
4、删除数据
const sqlStr = 'delete from users where id=?'
db.query(sqlStr,2,(err,results) => {
if(err) return console.log(err.message)
if(result.affectedRows ===1){ //判断数据是否插入成功
console.log('删除数据成功')
}
})
标记删除
const sqlStr = 'update users set status=? where id=?'
8、身份认证
cookie:存储在用户浏览器中的不超过4kb的字符串。
自动发送,域名独立,过期时限。
图解
浏览器(客户端) ------------>>>>>>登录请求--------------->>>>>服务器
浏览器(客户端)---------------<<<<<<通过响应头,发送Cookie给浏览器------<<<<---服务器
浏览器(将身份认证的cookie保存到浏览器中)--->>>通过请求头,自动将cookie发送给服务器----->>服务器(服务器根据请求头中cookie,验明用户的身份)------>>>>响应当前用户对应的内容
Session的工作原理
在浏览器中进行登录----提交账号和密码到服务器-----服务器验证账号和密码-----将登录成功后的用户信息存储在服务器内存中,同时生成对应的cookie字符串------将生成的cookie响应给客户端-----浏览器自动把cookie存储在当前域名下----客户端再次发送请求时,通过请求头自动把当前域名下所有可用的cookie发送给服务器----服务器根据请求头中携带的cookie,从内存中查找对应的用户信息------用户的身份信息认证成功之后,服务器针对当前用户生成特定的响应内容------把当前用户对应的页面内容响应给浏览器。
JWT认证机制
1、jwt工作原理
在浏览器中进行登录----提交账号和密码到服务器-----服务器验证账号和密码-----验证通过后将用户信息加密之后生成对应的Token字符串------将生成的Token响应给客户端-----将Token存储到LocalStorage或SessionStorage----客户端再次发送请求时,通过请求头的Authorization字段,将Token发送给服务器----服务器把Token字符串还原成用户的信息对象------用户的身份信息认证成功之后,服务器针对当前用户生成特定的响应内容------把当前用户对应的页面内容响应给浏览器。
2、jwt组成部分,逗号分割
Header.Payload.Signature
Payload:才是真正的用户信息
Header、Signature保证Token的安全性
3、使用方式
Authorization:Bearer <token>
在express中使用
npm i jsonwebtoken express-jwt
// 导入 express 模块
const express = require('express')
// 创建 express 的服务器实例
const app = express()
// TODO_01:安装并导入 JWT 相关的两个包,分别是 jsonwebtoken 和 express-jwt
const jwt = require('jsonwebtoken')
const expressJWT = require('express-jwt')
// 允许跨域资源共享
const cors = require('cors')
app.use(cors())
// 解析 post 表单数据的中间件
const bodyParser = require('body-parser')
app.use(bodyParser.urlencoded({ extended: false }))
// TODO_02:定义 secret 密钥,建议将密钥命名为 secretKey
const secretKey = 'zhangfan520'
// TODO_04:注册将 JWT 字符串解析还原成 JSON 对象的中间件
// 注意:只要配置成功了express-jwt这个中间件,就可以把解析出来的用户信息,挂载到req.user属性上
app.use(expressJWT({secret: secretKey }).unless({ path: [/^\/api\//] }))
// 登录接口
app.post('/api/login', function (req, res) {
// 将 req.body 请求体中的数据,转存为 userinfo 常量
const userinfo = req.body
// 登录失败
if (userinfo.username !== 'admin' || userinfo.password !== '000000') {
return res.send({
status: 400,
message: '登录失败!'
})
}
// 登录成功
const tokenStr = jwt.sign({ username: userinfo.username }, secretKey, { expiresIn: '1h' })
// TODO_03:在登录成功之后,调用 jwt.sign() 方法生成 JWT 字符串。并通过 token 属性发送给客户端
res.send({
status: 200,
message: '登录成功!',
token: tokenStr // 要发送给客户端的 token 字符串
})
})
// 这是一个有权限的 API 接口
app.get('/admin/getinfo', function (req, res) {
// TODO_05:使用 req.user 获取用户信息,并使用 data 属性将用户信息发送给客户端
console.log(req.user)
res.send({
status: 200,
message: '获取用户信息成功!',
data: req.user // 要发送给客户端的用户信息
})
})
// TODO_06:使用全局错误处理中间件,捕获解析 JWT 失败后产生的错误
app.use((err,req,res,next)=>{
if(err.name === 'UnauthorizedError'){
return res.send({
status:401,
message:'无效的Token'
})
}
res.send({
status:500,
message:'未知的错误'
})
})
// 调用 app.listen 方法,指定端口号并启动web服务器
app.listen(8888, function () {
console.log('Express server running at http://127.0.0.1:8888')
})

浙公网安备 33010602011771号