node.js服务端笔记文档学会写接口,学习分类:path、包、模块化、fs、express、中间件、jwt、开发模式、cors。
node.js 学习笔记
node.js服务端笔记文档学会写接口,path、包、模块化、fs、express、中间件、JWT、开发模式、cors。
gitee:代码接口笔记
1什么是node.js
- nodejs 是基于ChromeV8,引擎的一个javaScript 运行环境。
- node.js 无法使用DOM和BOM的浏览器进行操作。
fs模块
1 fs文件系统模块?
Fs 模块是node.js 官方提供的,用来操作文件的模块,他提供了一系列的方法和属性,用来满足用户对文件的操作需求。
1、readFile.radeFile()方法用来读取指定文件的内容。
const fs = require('fs');// 参数1, 是读取文件夹的路径类型是String类型。
// 参数2, 读取文件的采用的编码格式,一般为utf8格式。
// 参数3, 是一个回调函数,
// 回调函数第一参数是错误信息,如果null表示读取成功了,没有错误信息。一般判断null表示文件读取成功。
// 回调函数第二参数是文件内容,如果读取失败返回 undefined,否则读取文件内容成功。
fs.readFile('../File/文件.txt','utf8',(res, data) => {console.log(32455,res)if(res == null) {console.log('读取文件成功')console.log(324,data)}
})。
2、readFile.writFile() 方法用来向指定文件中写入内容的。
fs.writeFile 没有文件则进行创建文件,但是如果创建的路径中没有文件夹则会创建失败,有文件就进行追加内容,这个方法只能创建文件不能用来创建路径。
如果要在js中使用fs模块需要引入模块
const fs = require('fs')// 但是如果创建的路径中没有文件夹则会创建失败 [Error: ENOENT: no such file or directory, open '../File1/我爱你1.txt']
// 如果重复调用 writeFile 方法新的内容会吧原来的内容给覆盖掉。
// 参数一是读取文件的路径类型是String 必填选项。
// 参数二是往文件里写入的内容。
// 参数三是回调函数。// 回调函数参数第一个是返回的错误信息。默认返回null表示,文件写入成功没有错误信息。回调第二个参数是undefined。fs.writeFile('../File1/我爱你1.txt','我不爱你真的加的',(res) => {console.log(243,res)
})
3、__dirname解决路径拼接错误
在使用fs模块处理路径的时候。 如果使用相对路径会发生路径拼接错误的一些问题。原因就是在你去执行代码的时候,会执行node命令时所处的路径,动态拼接出操作文件的完整路径。
__dirname 表示当前文件夹所处的路径直接从盘符开始算起。
// cd ../ 返回上一层文件再去运行会报错
// Error: ENOENT: no such file or directory, open './1.txt'
// 因为nodejsnote 文件里没有 ../File/文件.txt// 解决方案就是,不要使用相对路经进行拼接,直接给出完整的一个路径。直接从盘符开始算起,他就没有这个相对路径拼接的一个问题了。因为你执行的时候,他就相对于当前文件去找他对应的一个文件。const fs = require('fs');
// __dirname 表示当前文件夹所处的路径直接从盘符开始算起。
console.log(4343,__dirname)fs.readFile(`${__dirname}/1.txt`,'utf8',(res, data) => {console.log(32455,res)if(res == null) {console.log('读取文件成功')console.log(324,data)}
})
path模块
- path 模块是nodejs官方提供,用来处理路径的,他提供了一系列的方法和属性,用来满足用户对于路径的处理。
- path.join([…path]) 用来将多个路径完整的拼接成一个字符串。
- path.basename(path,[ext]) 可以获取路径中的最后一部分,方法用来从路径字符串中,将中文名解析出来
- path.extname() 用来获取路径中的扩展名部分
const fs = require('fs');
const path = require('path')
// 表示当前文件夹所处的路径直接从盘符开始算起。
// `${__dirname}../fs/1.txt` => [Error: ENOENT: no such file or directory, open '/Users/sunzhihao/Desktop/nodejsnote/path../fs/1.txt']// `${__dirname}../fs/1.txt` => path.join(__dirname,'../fs/1.txt')console.log(4343,path.join(__dirname,'../fs/1.txt')) // /Users/sunzhihao/Desktop/nodejsnote/fs/1.txtfs.readFile(path.join(__dirname,'../fs/1.txt'),'utf8',(res, data) => {console.log(32455,res)if(res == null) {console.log('读取文件成功')console.log(324,data)}
})// 看输出
const fpath = '/a/b/c/index.html'
console.log(433,path.basename(fpath)) // 433 index.html
console.log(466,path.basename(fpath,'.html')) // 466 index
console.log(444,path.extname(fpath)) // 444 .html
http模块
http模块由nodejs提供,用来创建web服务的,通过http提供的http.createServer()方法,可以把一台电脑变为web服务器,对外部提供web资源。
1、什么是ip地址
ip地址指的是我们每台计算机的唯一地址,IP地址具有唯一性,类似于手机号,只有知道ip地址才能进行数据通信
IP地址格式通常用点分十进制。形成a.b.c.d 的性质,都是0-255的十进制。
互联网中的每台web服务器都有自己的IP的地址,可以输入 ping www.baidu.com 命令,可以查到百度服务器的IP地址
域名和Ip地址能够唯一标记网络上的计算机,单IP地址是一长串数字,不直观不好记,于是发明了字符行的地址方案,叫域名 Domain Name 地址
IP地址和域名是一一对应的关系。
域名服务器就是提供IP地址和域名之间的转换服务的服务器
127.0.0.1 == locallhost
2、端口号
计算机的端口号,就好像是现实生活中的门牌号一样,通过门牌号,外卖小哥可以把东西准确的送到你的手中。
一台电脑闹可以运行非常多的服务,每个web服务都有一个唯一的端口号,客户端发送过来的网络请求,通过端口号,可以准确的交给对应的web服务进行处理。
每个端口号不能同时被多个web服务占用。
url中的80端口可以省略
3、创建http服务
怎么启动服务 node index.js
node 加上文件名字就可以了
//引入我们的 http 模块
const http = require('http')
// 创建web 服务器
const server = http.createServer()// 为服务实例绑定 request 事件监听客户的请求
server.on('request', ( req, res) => {// const url = req.url// const method = req.method// 为了防止中文乱码设置响应头 鎮ㄧ殑url鏄�/璇锋眰鏂规硶鏄疓ETres.setHeader('Content-Type','text/html; charset=utf-8')// console.log('start server',url,method)// // 将内容返回给客户端// res.end(`您的url是${url}请求方法是${method}`)let content = '<h1>404 Not found</h1>'console.log('url',req.url)if(req.url == '/' || req.url == '/index.html') {content = '<h1>首页</h1>'}else if(req.url == '/about') {content = '<h1>about</h1>'}res.setHeader('Content-Type','text/html; charset=utf-8')res.end(content)
})// 启动服务
server.listen(8080,() => {console.log('server running at http://127.0.0.1:8080')
})
4、防止中文乱码设置响应头
// 为了防止中文乱码设置响应头 鎮ㄧ殑url鏄�/璇锋眰鏂规硶鏄疓ET
server.on('request', ( req, res) => {res.setHeader('Content-Type','text/html; charset=utf-8')
})
什么是包
1、包的概念
- Nodejs 中的第三方模块又叫包 相当于别名 (电脑等于计算机)
- 包是是第三方开发出来,免费供别人使用
- 由于node js 的内置模块仅提供了一些底层的API、导致基于内置模块开发慢,效率低
- 包是基于内置模块封装出来的,提供了更高级的更方便的api,提高开发效率
国外有一家IT公司叫做 npm inc 这家公司有个著名网站,http://www.npmjs.com/ 他是全球最大的包共享平台。
npm i moment 安装时间格式化的包
const moment = require('moment') 导入需要的包
moment().format('YYYY--MM-DD HH:mm:ss')
2、第一次安装包多了哪些文件
node_modules 文件用 来存放已经安装到项目中的包,require 导入第三方包,就是从这个目录开始查找并加载包的。
package-lock.json 配置文件用来记录 node_modules 目录下的每一个包的下载信息,列入包的名字,版本号,下载地址。
3、安装指定版本的包
通过@符号指定版本
npm install moment@2.0.0
4、包的版本号
是由 点分十进制定义的 2.0.0
第一位大版本
第二位 功能修复
第三位 bug 修复版本
只要版本号赠长了后面版本号就是 0
5、快速创建package.json
npm包管理工具提供了一个快捷命令,可以在执行命令时所处的目录中,快速创建package.json这个包管理
npm init -y
注意:
①上述命令只能在英文的目录下成功运行!所以,项目文件夹的名称一定要使用英文命名,不要使用中文,不能出现空格。
②运行npm install命令安装包的时候,npm包管理工具会自动把包的名称和版本号,记录到package.json中。npm规定,在项目根目录中,必须提供一个叫做package.json的包管理配置文件。用来记录与项目有关的一些配置
信息。例如:
·项目的名称、版本号、描述等
·项目中都用到了哪些包
·哪些包只在开发期间会用到
·那些包在开发和部署时都需要用到
6、npm install命令
可以运行npm install命令(或npmi)一次性安装所有的依赖包:
1/执行npm install命冷时,npm包管理工具会先读取package.json中的dependencies节点,
2/读取到记录的所有依赖包名称和版本号之后,npm包管理工具会把这些包一次性下载到项目中
3 npm install卸载包 npm uninstall moment
注意:npm uninstall命令执行成功后,会把卸载的包,自动从package.json的dependencies中移除掉。如果安装慢可以使用淘宝镜像 npm install --registry=https://registry.npm.taobao.org
当然也可以将淘宝镜像下载到本地
7、devDependencies节点
如果某些包只在项目开发阶段会用到,在项目上线之后不会用到,则建议把这些包记录到devDependencies节点中。
与之对应的,如果某些包在开发和项目上线之后都需要用到,则建议把这些包记录到dependencies节点中。
您可以使用如下的命令,将包记录到devDependencies节点中:安装指定的包,并记录到devDependencies节点中
npm 包名 -D
注意:上述命冷是简写形式,等价于下面完整的写法:
4 npm install 包名 --save-dev
npm install moment 默认会安装到里面 dependencies 里面开发和项目上线都会用到package.json dependencies 节点
专门介绍了安装了哪些包 如果你使用了moment包但是没有安装会报错 error : cannot find module moment
8、项目包
那些被安装到项目的node modules目录中的包,都是项目包。
项目包又分为两类,分别是:开发依赖包(被记录到devDependencies节点中的包,只在开发期间会用到)
核心依赖包(被记录到dependencies节点中的包,在开发期间和项目上线之后都会用到)
1 npm i 包名 -D
开发依赖包(会被记录到devDependencies节点下)
2 npm i 包名
核心依赖包(会被记录到dependencies节点下】
9、全局包
在执行npm install命令时,如果提供了-g参数,则会把包安装为全局包。
全局包会被安装到C.\Users用户目录AppData\Roaming\npm\node modules目录下。
1 npm i包名-g
#全局安装指定的包
2 npm uninstall包名-g 卸载全局安装的包
注意:
①只有工具性质的包,才有全局安装的必要性。因为它们提供了好用的终端命令。
10、规范的包结构
在清楚了包的概念、以及如何下载和使用包之后,接下来,我们深入了解一下包的内部结构。
一个规范的包,它的组成结构,必须符合以下3点要求:
①
包必须以单独的目录而存在
②
包的顶级目录下要必须包含package.json这个包管理配置文件
③package.json中必须包含name,version,main这三个属性,分别代表包的名字、版本号、包的入口。
注意:以上3点要求是一个规范的包结构必须遵守的格式,关于更多的约束,可以参考如下网址:
https://yarnpkg.com/zh-Hans/docs/package-json
模块化
模块化的概念
模块化指的是解决一个复杂的问题时候,从顶层向下逐层把系统分成若干模块的过程,对于整个系统来说,模块可以租合,可以分解,可以更换的单元。
在代码中模块化就是遵守固定的规则,把一个大文件拆成独立独立相互依赖的多个小模块。
好处
提高代码的可维护性 可复用性 按需加载
如果大家都遵循同样的模块化代码规范,可以降低大家之间的沟通成本极大方便了各个模块的相互调用。
模块化的规范指的就是 使用什么样的方式向外暴露成员 使用什么样的语法格式来引用模块。
模块化又分为
内置模块 内置模块是nodejs提供的例如 fs path http
自定义模块 用户创建的每个.js文件称为自定义模块
第三方模块 (由第三方开发出来的模块,并非官方提供的,也不是自己创建的,使用的话需下载)
加载模块
加载模块使用require()方法可以加载需要的内置模块,用户自定义模块,第三方模块
使用require() 方法加载其他模块时,会执行被加载模块重的代码
const fs = require(‘fs’) 加载内置模块
const fs = require(‘./index.js’) 加载用户自定义模块 使用require方法可以省略js后缀名
const _ = require(‘lodash’) 加载第三方模块
模块化作用域
和函数作用域类似,在自定义模块中定义的变量,方法,只能在当前模块中访问无法被外界访问,这种模块级别的访问限制叫做模块化作用域。
module 对象
-
每个.js 自定义模块都有一个module对象,它里面存储了和当前模块有关信息
-
node.js 遵循了commonjs模块规范化,commonjs 规定了模块的特性和各模块之间如何相互依赖
-
每个模块内部module变量代表当前模块
-
module变量是一个对象 它的 exports 属性 等于 module.exports = 是对外的接口
-
require 是用来加载模块的
-
console.log(module)
// 打印
Module {id: '.',path: '/Users/sunzhihao/Desktop/nodejsnote/模块化',exports: {},parent: null,filename: '/Users/sunzhihao/Desktop/nodejsnote/模块化/模块化的基本概念.js',loaded: false,children: [],paths: ['/Users/sunzhihao/Desktop/nodejsnote/模块化/node_modules','/Users/sunzhihao/Desktop/nodejsnote/node_modules','/Users/sunzhihao/Desktop/node_modules','/Users/sunzhihao/node_modules','/Users/node_modules','/node_modules']
}
向外共享模块作用域中的成员
// module.exports 在自定义模块可以通过 module.exports 将模块内的成员给共享出去,共外界使用。
// 在外界使用require方法导入自定义模块时,得到的就是module.export 所指的对象。// 文件1 代码
module.exports.aa = '我是数据'
// 文件2 代码
const a = require('./1')
console.log(a) // { aa: '我是数据' }// 共享成员的注意点 导入的结果永远以 module.exports = 指向的对象为准
// 文件1 代码
module.exports.aa = '我是数据'
module.exports = {bb:333
}
// 文件2 代码const a = require('./1')
console.log(a) // { aa: '我是数据' }
exports 对象
// 由于module.exports写的复杂,为了简化成员,node提供了exports对象
// module.exports 和 exports指向的同一个对象 结果永远以 module.exports = 指向的对象为准// 文件1 代码
exports.aa = '我是数据'// 文件2 代码
const a = require('./1')
console.log(a) // { aa: '我是数据' }
模块的加载机制
内置模块的加载机制
内置模块是由Node.js官方提供的模块,内置模块的加载优先级最高。
例如,require('fs)始终返回内置的fs模块,即使在node modules目录下有名字相同的包也叫做fs。
自定义模块的加载机制
使用require加载自定义模块时,必须指定以./或…/开头的路径标识符。在加载自定义模块时,如果没有指定./或…/
这样的路径标识符,则node会把它当作内置模块或第三方模块进行加载。
同时,在使用require导入自定义模块时,如果省略了文件的扩展名,则Node.js会按顺序分别尝试加载以下的文件:
①按照确切的文件名进行加载
②补全js扩展名进行加载
③补全json扩展名进行加载
④补全node扩展名进行加载
⑤加载失败,终端报错
第三方模块的加载机制
如果传递给require 的模块标识符不是一个内置模块,也没有以’./”或’…/'开头,则Node.js会从当前模块的父
目录开始,尝试从/node modules文件夹中加载第三方模块。
如果没有找到对应的第三方模块,则移动到再上一层父目录中,进行加载,直到文件系统的根目录。
例如,假设在’C.Users\itheima\project\foo.js’文件里调用了require('tools),则Node.js会按以下顺序查找:
①C:\Users\itheima\project\node modules\tools
②C:\Users\itheima\node modules\tools
③C:\Users\node modules\tools
4C:\node modules\tools
找不到报错
目录作为模块
当把目录作为模块标识符,传递给require 进行加载的时候,有三种加载方式:
①在被加载的目录下查找一个叫做package.json的文件,并寻找main属性,作为require加载的入口
②如果目录里没有package.json文件,或者main入口不存在或无法解析,则Node.js将会试图加载目录下的index.js文件。
③如果以上两步都失败了,则Node.js会在终端打印错误消息,报告模块的缺失:Error:Cannot find module ‘Xx’
{
"name": "pack",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"moment": "^2.29.4"
}}main 设置aaa.js 找对应文件夹里的 /aaa.js
没有设置 main 默认找 index.js
注意 json 中不能使用单引号
Express 服务端框架
什么是express
官方给出的概念:Express是基于Node.js平台,快速、开放、极简的Web开发框架。
通俗的理解:Express的作用和Node.js内置的http模块类似,是专门用来创建Web服务器的。
Express的本质:就是一个npm上的第三方包,提供了快速创建Web服务器的便捷方法。
Express的中文官网:http:lwww.expressjs.com.cnl
进一步理解Express
思考:不使用Express能否创建Web服务器?
答案:能,使用Node.js提供的原生http模块即可。
思考:既生瑜何生亮(有了http内置模块,为什么还有用Express)?
答案:http内置模块用起来很复杂,开发效率低;Express是基于内置的http模块进一步封装出来的,能够极大的提高开发效率。
思考:http内置模块与Express是什么关系?
答案:类似于浏览器中Neb API和jQuery的关系。后者是基于前者进一步封装出来的。
Express能做什么
对于前端程序员来说,最常见的两种服务器,分别是:
Web网站服务器:专门对外提供Web网页资源的服务器。
AP接口服务器:专门对外提供API接口的服务器。
使用Express,我们可以方便、快速的创建Web网站的服务器或API接口的服务器。
安装nodemon
在终端中,运行如下命令,即可将nodemon安装为全局可用的工具:
npm install -g nodemon
使用nodemon
当基于Node.js编写了一个网站应用的时候,传统的方式,是运行node app.js命令,来启动项目。这样做的坏处是:
代码被修改之后,需要手动重启项目。
现在,我们可以将node命令替换为nodemon命令,使用nodemon app.js来启动项目。这样做的好处是:代码
被修改之后,会被nodemon监听到,从而实现自动重启项目的效果。
node app.js
将上面的终端命令,替换为下面的终端命令,即可实现自动重启项目的效果
nodemon app.js
创建express定义get接口
创建文件夹
npm init -y
{"name": "demo","version": "1.0.0","main": "index.js","scripts": {"dev": "nodemon index.js"},"keywords": [],"author": "","license": "ISC","description": "","dependencies": {"body-parser": "^1.20.1","express": "^4.18.2","nodemon": "^2.0.20"}
}
npm install
启动 npm run dev
index.js 创建服务
const express = require('express')
const app = express()// 前端问号拼接参数
app.get('/user', (req, res) => {// 前端访问 http://localhost/user?id=232423&kk=9999// req.query 可以接收到前端传来的参数默认是一个空对象console.log(req.query) // { id: '232423', kk: '9999' }// res.send 向前端发送数据res.send({ name: 'get', age: 20 })
})//获取URL中的动态参数
app.get('/banner/:id/:name', (req, res) => {// 前端访问 url http://localhost/banner/123/szh//通过req.params对象,可以访问到URL中,通过:匹配到的动态参数:console.log(req.params) // { id: '123', name: 'szh' }// res.send 向前端发送数据res.send({ name: 'get', age: 20 })
})app.listen(80, () => { // 监听80端口console.log('启动成功 http://localhost')
})
创建express定义post接口
const express = require('express')
const app = express()
app.post('/list', (req, res) => {res.send({ name: 'post', age: 20 })
})
app.listen(80, () => { // 监听80端口console.log('启动成功 http://localhost')
})
创建express定义post接口获取参数undefined
- 使用内置中间件解决
- 注意json属性名一定要加上双引号
const express = require('express')
const app = express()//注意:除了错误的中间件,其他的中间件,必须在路由之前进行配置app.use(express.json()) // 不配置req.body 拿不到json数据app.use(express.urlencoded({extended:false})) // 可以解析form-data的数据url-encode格式的数据app.post('/list', (req, res) => {// req.body 可以拿到前端传过来的请求体 json 格式的console.log(23234, req.body) // undefined// 如果默认不配置解析表单数据的中间件,则req.body 值为 undefined// 可以解析json但是无法解析url-encode格式的数据 form-data 格式的数据 不是那种对象包裹的数据// 使用中间件app.use(express.urlencoded({extended:false}))res.send({ name: 'post', age: 20 })
})app.listen(80, () => {console.log('启动成功 http://172.0.0.1')
})
也可以使用第三方的中间件解决req.body 值为 undefined
npm i
body-parser
"body-parser": "^1.20.1",
const bodyParser = require('body-parser')
app.use(bodyParser.urlencoded({extended:false}))
托管静态资源
express.static()
express提供了一个非常好用的函数,叫做express.static通过它,我们可以非常方便地创建一个静态资源服务器,
例如,通过如下代码就可以将public目录下的图片、CSS文件、JavaScript文件对外开放访问了:
app.use(express.static('public'))
现在,你就可以访问public目录中的所有文件了:
http://localhost:3000/images/bg.jpg
http://localhost:3000/css/style.css
http://localhost:3000/js/login.js
注意:Express在指定的静态目录中查找文件,并对外提供资源的访问路径。
因此,存放静态文件的目录名不会出现在URL中。
托管多个静态资源目录
如果要托管多个静态资源目录,请多次调用express…static0函数:
访问静态资源文件时,express.static函数会根据目录的添加顺序查找所需的文件。
public 文件找不到就去找file文件
app.use(express.static(‘./public’))
app.use(express.static(‘./file’))
http://localhost/index1.html 可以访问
托管静态资源挂载路径前缀
如果希望在托管的静态资源访问路径之前,挂载路径前缀,则可以使用如下的方式:
app.use(‘/public’,express.static(‘./public’))
现在,你就可以通过带有/public前缀地址来访问public目录中的文件了:
http://localhost:3000/public/images/kitten.jpg
http://localhost:3000/public/css/style.css
http://localhost:3000/public/js/app.js
http://localhost/public/index1.html
路由的概念
3.Express中的路由
在Express中,路由指的是客户端的请求与服务器处理函数之间的映射关系。
Express中的路由分3部分组成,分别是请求的类型、请求的URL地址、处理函数,格式如下:
1 app.METHOD(PATH,HANDLER)
使用router路由模块
模块化路由
为了方便对路由进行模块化的管理,Express不建议将路由直接挂载到app上,而是推荐将路由抽离为单独的模块。
将路由抽离为单独模块的步骤斁如下:
①创建路由模块对应的js文件
②调用express.Router()函数创建路由对象
③向路由对象上挂载具体的路由
④使用module.exports向外共享路由对象
⑤使用app.use()函数注册路由模块
router.js
const express = require('express')
var router = express.Router() // 使用路由而不是 expressrouter.get('/getList/list',function (req,res) {res.send('get list success')
})router.get('/getBanner/list',function (req,res) {res.send('get banner success')
})module.exports = router // 通过module对象将router抛出去
Index.js
const express = require('express')
const app = express()const getList = require('./router')
app.use(getList) // app.use 用来注册路由// app.use('/api', getList) 如果想要有统一前缀第一个参数// 访问就要在路径前面加上 /qpi http://localhost/api/getBanner/listapp.listen(80, () => {console.log('启动成功 http://172.0.0.1')
})
中间件
什么是中间件
中间件指的是中间处理业务部分的逻辑
Express中间件的调用流程
当一个请求到达Express的服务器之后,可以连续调用多个中间件,从而对这次请求进行预处理。
请求 > 中间件1 > 中间件2 > 处理响应 > 处理完毕响应 > 请求客户端
中间件的概念
Express的中间件,本质上就是一个function处理函数,Express中间件的格式如下:
next函数是实现多个中间件连续调用的关键,它表示把流转关系转交给下一个中间件或路由。
app.post('/list', (req, res, next) => {
res.send({name:'post',age:20})
})
注意:中间件函数的形参列表中,必须包含next参数。而路由处理函数中只包含req和res。
中间件的作用
多个中间件之间,共享同一份req和res。基于这样的特性,我们可以在上游的中间件中,统一为req或res对象添
加自定义的属性或方法,供下游的中间件或路由进行使用。
局部生效的中间件
const express = require('express')
const app = express()
const middleware = function (req, res, next) {console.log('我是局部中间件')// 处理逻辑next() // 调用表示可以执行下面这个接口
}app.get('/user', middleware, (req, res) => {res.send({ a: '局部中间件' })
})
app.listen(80, () => {console.log('启动成功 http://172.0.0.1')
})
定义多个局部中间件
// 可以在路由中,通过如下两种等价的方式,使用多个局部中间件:
//以下两种写法是"完全等价"的,可根据自己的喜好,选择任意一种方式进行使用
const mw1 = function (req, res, next) {console.log('我是局部中间件1')// 处理逻辑next() // 调用表示可以执行下面这个接口
}
const mw2 = function (req, res, next) {console.log('我是局部中间件2')// 处理逻辑next() // 调用表示可以执行下面这个接口
}
// 定义一个数组传入中间件函数
app.get('/'mw1,mw2,(req,res)=>res.send('Home page.')}
app.get('/',[mw1,mw2],(req,res)=>{res.send('Home page.')
定义全局中间
定义全局中间件中间件成功就会进行下一步
中间件相当于vue 的路由拦截
const express = require('express')
const app = express()
const mw = function (req, res, next) {
console.log('第一个中间件')
// next() 不使用next() 报错: textStatus: timeout连接网络时发生异常: http://localhost/api/getBanner/list
// 通过req可以添加属性和方法 让下一个接口使用
let time = new Date().getTime()
req.time = timenext()
}
app.use(mw) // 注册全局中间件
中间件传递数据
const express = require('express')
const app = express()const mw = function (req, res, next) {
let time = new Date().getTime()
req.time = timenext()
}
// list 接口
app.post('/list', (req, res) => {console.log('可以拿到中间件添加的属性', req.time) // 可以拿到中间件添加的属性 1675137876666res.send({ name: 'post', age: 20 })
})app.use(mw) // 注册全局中间件app.listen(80, () => {console.log('启动成功 http://172.0.0.1')
})
定义多个全局中间件
可以使用app.use 连续定义多个全局中间件。客户端请求到达服务器之后,会按照中间件定义的先后顺序依次进行
调用,示例代码如下:
const express = require('express')
const app = express()
// 可以定义第二个中间件 放到第一个中间件的下面即可
app.use((req, res, next) => {
console.log('第二个中间件')
next()
})
了解中间件的5个使用注意事项
①一定要在路由之前注册中间件
②客户端发送过来的请求,可以连续调用多个中间件进行处理
③执行完中间件的业务代码之后,不要忘记调用next0函数
④为了防止代码逻辑混乱,调用next0函数后不要再写额外的代码
⑤连续调用多个中间件时,多个中间件之间,共享req和res对象
中间件的分类
为了方便大家理解和记忆中间件的使用,Express官方把常见的中间件用法,分成了5大类,分别是:
①应用级别的中间件
②路由级别的中间件
③错误级别的中间件
④Express内置的中间件
⑤第三方的中间件
1.应用级别的中间件
通过app.use或app.get或app.post,绑定到app实例上的中间件,叫做应用级别的中间件.
2.路由级别的中间件
绑定到express.Router(实例上的中间件,叫做路由级别的中间件。它的用法和应用级别中间件没有任何区别。只不
过,应用级别中间件是绑定到app实例上,路由级别中间件绑定到router实例上.
3.错误级别的中间件
错误级别中间件的作用:专门用来捕获整个项目中发生的异常错误,从而防止项目异常崩溃的问题。
格式:错误级别中间件的function处理函数中,必须有4个形参,形参顺序从前到后,分别是(error,req,res,next)。
注意错误中间件必须放在所有的接口最下面执行,其他中间件可以放到最上面。
const express = require('express')
const app = express()// 接口代码 报错会被错误级别的中间件 捕获 而不会让整个项目无法启动
app.get('/error', (req, res) => {throw new Error('服务器错误')res.send({ a: 24324 })
})app.use(function (error, req, res, next) {console.log('error.message', error)res.send({ error: error.message })// 服务器错误next()
})
app.listen(80, () => {console.log('启动成功 http://172.0.0.1')
})
4.Express内置的中间件
自Express4.16.0版本开始,Express内置了3个常用的中间件,极大的提高了Express项目的开发效率和体验:
①express…static快速托管静态资源的内置中间件,例如:HTML文件、图片、CSS样式等(无兼容性)
②express.json解析JSON格式的请求体数据(有兼容性,仅在4.16.0+版本中可用)
③express.urlencoded解析URL-encoded格式的请求体数据(有兼容性,仅在4.16.0+版本中可用)
配置解析application./json格试数据的内置中间件
2
app.use(express.json())
配置解析application/x-www-form-urlencoded格式数据的内置中间件
4
app.use(express.urlencoded({extended:false })
5.第三方的中间件是别人编写的你来使用。
也可以使用第三方的中间件解决req.body 值为 undefined
npm i
body-parser
无法解析req.body可以替换
第三方的中间件
非Express官方内置的,而是由第三方开发出来的中间件,叫做第三方中间件。在项目中,大家可以按需下载并配置
第三方中间件,从而提高项目的开发效率。
例如:在express(@4.16.0之前的版本中,经常使用body-parser这个第三方中间件,来解析请求体数据。使用步
骤如下:
①运行npm install body-parser安装中间件
②使用require导入中间件
③调用app.use0注册并使用中间件"body-parser": "^1.20.1",
const bodyParser = require('body-parser')
app.use(bodyParser.urlencoded({extended:false}))
http请求
http请求分为三部分:请求行,请求头, 请求体
请求行:
是请求方法,GET和POST是最常见的HTTP方法,除此以外还包括DELETE、HEAD、OPTIONS、PUT、TRACE。
为请求对应的URL地址,它和报文头的Host属性组成完整的请求URL。
是协议名称及版本号。
请求头
HTTP的报文头,报文头包含若干个属性,格式为“属性名:属性值”,服务端据此获取客户端的信息。
与缓存相关的规则信息,均包含在header中
请求体:
报文体,它将一个页面表单中的组件值通过param1=value1¶m2=value2的键值对形式编码成一个格式化串,它承载多个请求参数的数据。不但报文体可以传递请求参数,请求URL也可以通过类似于“/chapter15/user.html? param1=value1¶m2=value2”的方式传递请求参数。
常见的请求头
Accept: 览器支持的 MIME 媒体类型, 比如 text/html,application/json,image/webp,/ 等(比如text/plain只支持文本的数据)
Accept-Encoding: 浏览器发给服务器,声明浏览器支持的编码类型,gzip, deflate
Accept-Language: 客户端接受的语言格式,比如 zh-CN
Connection: keep-alive , 开启HTTP持久连接
Host:服务器的域名
Origin:告诉服务器请求从哪里发起的,仅包括协议和域名 CORS跨域请求中可以看到response有对应的header,Access-Control-Allow-Origin
Referer:告诉服务器请求的原始资源的URI,其用于所有类型的请求,并且包括:协议+域名+查询参数; 很多抢购服务会用这个做限制,必须通过某个入来进来才有效
User-Agent: 服务器通过这个请求头判断用户的软件的应用类型、操作系统、软件开发商以及版本号、浏览器内核信息等; 风控系统、反作弊系统、反爬虫系统等基本会采集这类信息做参考
Cookie: 表示服务端给客户端传的http请求状态,也是多个key=value形式组合,比如登录后的令牌等
Content-Type: HTTP请求提交的内容类型,一般只有post提交时才需要设置,比如文件上传,表单提交等
响应头
报文头包含若干个属性 格式为“属性名:属性值”
常见的响应头
Allow: 服务器支持哪些请求方法
Content-Length: 响应体的字节长度
Content-Type: 响应体的MIME类型
Content-Encoding: 设置数据使用的编码类型
Date: 设置消息发送的日期和时间
Expires: 设置响应体的过期时间,一个GMT时间,表示该缓存的有效时间
cache-control: Expires的作用一致,都是指明当前资源的有效期, 控制浏览器是否直接从浏览器缓存取数据还是重新发请求到服务器取数据,优先级高于Expires,控制粒度更细,如max-age=240,即4分钟
Location:表示客户应当到哪里去获取资源,一般同时设置状态代码为3xx
Server: 服务器名称
Transfer-Encoding:chunked 表示输出的内容长度不能确定,静态网页一般没,基本出现在动态网页里面
Access-Control-Allow-Origin: 定哪些站点可以参与跨站资源共享
Content-type
用来指定不同格式的请求响应信息,俗称 MIME媒体类型
常见的取值
text/html :HTML格式
text/plain :纯文本格式
text/xml : XML格式
image/gif :gif图片格式
image/jpeg :jpg图片格式
image/png:png图片格式
application/json:JSON数据格式
application/pdf :pdf格式
application/octet-stream :二进制流数据,一般是文件下载
application/x-www-form-urlencoded:form表单默认的提交数据的格式,会编码成key=value格式
multipart/form-data: 表单中需要上传文件的文件格式类型
CORS跨域资源共享
接口的跨域问题
刚才编写的GET和POST接口,存在一个很严重的问题:不支持跨域请求。
只要协议 域名 端口有一个不一致就会发生跨域。
解决接口跨域问题的方案主要有两种:
①CORS(主流的解决方案,推荐使用)
②JSONP(有缺陷的解决方案:只支持GET请求)
使用cors中间件解决跨域问题
cors是Express的一个第三方中间件。通过安装和配置cors中间件,可以很方便地解决跨域问题。
使用步骤分为如下3步:
①运行npm install cors安装中间件
②使用const cors=require(cors)导入中间件
③在路由之前调用app.use(cors())配置中间件const cors = require('cors') // cors解决跨域问题
app.use(cors())
什么是CORS
CORS(Cross-Origin Resource Sharing)跨域资源共享由一系列HTTP响应头组成,这些HTTP响应头决定
浏览器是否阻止前端JS代码跨域获取资源。
浏览器的同源安全策略默认会阻止网页“跨域”获取资源。但如果接口服务器配置了CORS相关的HTTP响应头,
就可以解除浏览器端的跨域访问限制。
CORS的注意事项
①CORS主要在服务器端进行配置。客户端浏览器无须做任何额外的配置,即可请求开启了CORS的接口。
②CORS在浏览器中有兼容性。只有支持XMLHttpRequest Level2的浏览器,才能正常访问开启了CORS的服
务端接口(例如:IE10+、Chrome4+、FireFox3.5+)。
JSONP的概念与特点
概念:浏览器端通过
CORS响应头部
CORS响应头部Access–Control-Allow-Origin
// 5.CORS响应头部-Access-Control-Allow-Origin
// 如果指定了Access--Control-Allow-Origin字段的值为通配符*,表示允许来自任何域的请求,示例代码如下:
res.setHeader('Access-Control-Allow-Origin','*')// 全局中间件
app.use(function (req,res,next) {res.setHeader('Access-Control-Allow-Origin','*')res.setHeader('Access-Control-Allow-Headers','Content-Type,X-Custom-Header')next()
})
CORS响应头部-Access-Control-Allow-Headers
默认情况下,CORS仅支持客户端向服务器发送如下的9个请求头:
Accept、Accept-Language、Content-Language、DPR、Downlink、Save-Data、Viewport-Width、Width、
Content-Type(值仅限于text/plain、multipart/form-data、application./x-www-form-urlencoded三者之一)
如果客户端向服务器发送了额外的请求头信息,则需要在服务器端,通过Access-Control–Allow-Headers对额外
的请求头进行声明,否则这次请求会失败!
允许客户端额外向服务器发送Content-Type请求头和X-Custom-Header请求头
注意:多个请求头之间使用英文的逗号进行分割
res.setHeader('Access-Control-Allow-Headers','Content-Type,X-Custom-Header')
CORS响应头部- Access-Control-Allow-Methods
默认情况下,CORS仅支持客户端发起GET、POST、HEAD请求。
如果客户端希望通过PUT、DELETE等方式请求服务器的资源,则需要在服务器端,通过 Access-Contro-Alow-Methods
来指明实际请求所允许使用的HTTP方法。
示例代码如下:
只允许POST、GET、DELETE、HEAD清求方法res.setHeader('Access-Control-Allow-Methods','POST,GET,DELETE,HEAD')允许所有的HTTP清求方法res.setHeader('Access-Control-Allow-Methods','*')
同时满足以下两大条件的情求,就属于简单请求:
①请求方式:GET、POST、HEAD三者之一
②HTTP头部信息不超过以下几种字段:
无自定义头部字段、Accept、Accept-Language、Content-Language、DPR、Downlink、Save-Data、Viewport-Width、Width、
Content-Type(只有三个值application/x-www-form-urlencoded, multipart/form-data, text/plain)
预检请求
公只要符合以下任何一个条件的请求,都需要进行预检请求:
①请求方式为GET、POST、HEAD之外的请求Method类型
②请求头中包含自定义头部字段
③向服务器发送了application/json格式的数据
在浏览器与服务器正式通信之前,浏览器会先发送OPTION请求进行预检,以获知服务器是否允许该实际请求,所以这一
次的OPTION请求称为“预检请求”。服务器成功响应预检请求后,才会发送真正的情求,并目携带真实数据。
简单请求的特点:客户端与服务器之间只会发生一次请求。
预检请求的特点:客户端与服务器之间会发生两次请求,OPTION预检请求成功之后,才会发起真正的请求。
delete 走两遍请求
Request Method: OPTIONS
Request Method: DELETE
Jwt
安装JWT相关的包
运行如下命令,安装如下两个JWT相关的包:
npm install jsonwebtoken express-jwt
其中:
jsonwebtoken用于生成JWT字符串
express-jwt用于将JWT字符串解析还原成JSON对象
“jsonwebtoken”: “^8.5.1”,
“@escook/express-joi”: “^1.1.1”
什么是JWT
WT(英文全称:JSON Web Token)是目前最流行的跨域认证解决方案。
总结:用户的信息通过Token字符串的形式,保存在客户端浏览器中。服务器通过还原Tokn字符串的形式来认证用户的身份。
JWT的组成部分
JWT通常由三部分组成,分别是Header(头部)、Payload(有效荷载)、Signature(签名)。
JWT的三个部分各自代表的含义(token 的组成)
JWT的三个组成部分,从前到后分别是Header、Payload、Signature。
其中:
Payload部分才是真正的用户信息,它是用户信息经过加密之后生成的字符串。
·Header和Signature是安全性相关的部分,只是为了保证Token的安全性。
JWT的web使用方式
客户端收到服务器返回的JWT之后,通常会将它储存在localStorage或sessionStorage中。
此后,客户端每次与服务器通信,都要带上这个WT的字符串,从而进行身份认证。推荐的做法是把JWT放在HTTP
请求头的Authorization字段中,格式如下:
Authorization: Bearer + token
JWT服务端使用方式
const express = require('express')
const app = express()// 安装并且导入JWT的两个包
const jwt = require('jsonwebtoken')
const expressJWTfn = require('express-jwt')// 定义secret密钥
const secretKey = 'woshimima'// 解密
// 将JWT字符串还原为JSON对象
// 客户端每次在访问那些有权限接口的时候,都需要主动通过请求头中的Authorization字段,将Token字符串发
// 送到服务器进行身份认证。
// 此时,服务器可以通过express-jwt这个中间件,自动将客户端发送过来的Token解析还原成SON对象:
// 1使用app.use()来注册冲间件
// 2 expressJWT({secret:secretKey})就是用来解析Token的中间件
// 3 unless({path:[/^\/api\/]})用来指定哪些接口不需要访问权限
// 4 app.use(expressJWT({secret:secretKey }).unless({path:[/a\/api\//]})
// 注意 只要使用expressJWT中间件就可以解析出来用户对象挂在到req.user身上// 使用 .unless({ path: [/^\/api\//] }) 指定哪些接口不需要进行 Token 的身份认证
app.use(expressJWT({ secret: jwtSecretKey }).unless({ path: [/^\/api\//] }))/*.在登录成功后生成JWT字符串调用jsonwebtoken包提供的sign方法,将用户的信息加密成JWT字符串,响应给客户端:参数1:用户的信息对象参数2:加密的秘钥参数3:配置对象,可以配置当前token的有效期 30s 1h*/// 注意:不要把密码加入到token加密中const tokenStr = jwt.sign({ username: req.body.username }, secretKey, { expiresIn: '30s' })
res.send({ success: '登陆成功', code: 200, token: tokenStr })
开发模式
服务端渲染的Web开发模式
服务端渲染的概念:服务器发送给客户端的HTML页面,是在服务器通过字符串的拼接,动态生成的。因此,客户端不
需要使用Ajax这样的技术额外请求页面的数据。
服务端渲染的优缺点
优点:
①前端耗时少。因为服务器端负责动态生成HTML内容,浏览器只需要直接渲染页面即可。尤其是移动端,更省电。
②有利于SEO。因为服务器端响应的是完整的HTML页面内容,所以爬虫更容易爬取获得信息,更有利于SEO。
缺点:
①占用服务器端资源。即服务器端完成HTML页面内容的拼接,如果请求较多,会对服务器造成一定的访问压力。
②不利于前后端分离,开发效率低。,使用服务器端渲染,则无法进行分工合作,尤其对于前端复杂度高的项目,不利于
项目高效开发。
前后端分离的Web开发模式
前后端分离的概念:前后端分离的开发模式,依赖于Ajax技术的广泛应用。简而言之,前后端分离的Wb开发模式,
就是后端只负责提供API接口,前端使用AjaX调用接口的开发模式。
4.前后端分离的优缺点
优点:
①开发体验好。前端专注于U川页面的开发,后端专注于pi的开发,且前端有更多的选择性。
②用户体验好。Ajx技术的广泛应用,极大的提高了用户的体验,可以轻松实现页面的局部刷新。
③减轻了服务器端的渲染压力。因为页面最终是在每个用户的浏览器中生成的。
缺点:
①不利于SEO。因为完整的HTML页面需要在客户端动态拼接完成,所以爬虫对无法爬取页面的有效信息。(解决方
案:利用Vue、React等前端框架的SSR(server side render)技术能够很好的解决SEO问题!)
如何选择Web开发模式
不谈业务场景而盲目选择使用何种开发模式都是耍流氓。
比如企业级网站,主要功能是展示而没有复杂的交互,并且需要良好的SEO,则这时我们就需要使用服务器端渲染;
而类似后台管理项目,交互性比较强,不需要考虑SEO,那么就可以使用前后端分离的开发模式。
另外,具体使用何种开发模式并不是绝对的,为了同时兼顾了首页的渲染速度和前后端分离的开发效率,一些网站采用了
首屏服务器端渲染+其他页面前后端分离的开发模式。
身份认证
什么是身份认证
身份认证(Authentication)又称"身份验证”、"鉴权”,是指通过一定的手段,完成对用户身份的确认。
日常生活中的身份认证随处可见,例如:高铁的验票乘车,手机的密码或指纹解锁,支付宝或微信的支付密码等。
在Web开发中,也涉及到用户身份的认证,例如:各大网站的手机验证码登录、邮箱密码登录、二维码登录等。
为什么需要身份认证
身份认证的目的,是为了确认当前所声称为某种身份的用户,确实是所声称的用户。例如,你去找快递员取快递,你要怎么证明这份快递是你的。
在互联网项目开发中,如何对用户的身份进行认证,是一个值得深入探讨的问题。例如,如何才能保证网站不会错误的将“马云的存款数额”显示到“马化腾的账户”上。
不同开发模式下的身份认证
对于服务端渲染和前后端分离这两种开发模式来说,分别有着不同的身份认证方案:
①服务端渲染推荐使用Session认证机制
②前后端分离推荐使用JWT认证机制
HTTP协议的无状态性
了解HTTP协议的无状态性是进一步学习Session认证机制的必要前提。
HTTP协议的无状态性,指的是客户端的每次HTTP请求都是独立的,连续多个请求之间没有直接的关系,服务器不会主动保留每次HTTP请求的状态。
如何突破HTTP无状态的限制
对于超市来说,为了方便收银员在进行结算时给VIP用户打折,超市可以为每个VP用户发放会员卡。
辨别用户的VIP身份
注意:现实生活中的会员卡身份认证方式,在Web开发中的专业术语叫做Cookie。
了解Session认证的局限性
Session认证机制需要配合Cookie才能实现。由于Cookie默认不支持跨域访问,所以,当涉及到前端跨域请求后端接
口的时候,需要做很多额外的配置,才能实现跨域Session认证。
注意:
·当前端请求后端接口不存在跨域问题的时候,推荐使用Session身份认证机制。
·当前端需要跨域请求后端接口的时候,不推荐使用Session身份认证机制,推荐使用WT认证机制。
什么是Cookie
Cookie是存储在用户浏览器中的一段不超过4KB的字符串。它由一个名称(Name)、一个值(Value)和其它几个用
于控制Cookie有效期、安全性、使用范围的可选属性组成。
不同域名下的Cookie各自独立,每当客户端发起请求时,会自动把当前域名下所有未过期的Cookie一同发送到服务器。
Cookiel的几大特性:
自动发送
域名独立
过期时限
k4b限制
Cookie在身份认证中的作用
客户端第一次请求服务器的时候,服务器通过响应头的形式,向客户端发送一个身份认证的Cookie,客户端会自动
将Cookie保存在浏览器中。
随后,当客户端浏览器每次请求服务器的时候,浏览器会自动将身份认证相关的Cook,通过请求头的形式发送给
服务器,服务器即可验明客户端的身份。
Cookie不具有安全性
由于Cookie是存储在浏览器中的,而且浏览器也提供了读写Cookie的AP叫,因此Cookie很容易被伪造,不具有安全
性。因此不建议服务器将重要的隐私数据,通过Cookie的形式发送给浏览器。
注意:干万不要使用Cookie存储重要且隐私的数据!比如用户的身份信息、密码等。
提高身份认证的安全性
为了防止客户伪造会员卡,收银员在拿到客户出示的会员卡之后,可以在收银机上进行刷卡认证。只有收银机确认存在的
会员卡,才能被正常使用。
这种“会员卡+刷卡认证”的设计理念,就是Session认证机制的精髓。
nodejs 怎么连接mysql数据库
const express = require('express') //引入express 模块
const app = express() //创建实例
const mysql = require('mysql') //引入mysql 模块
// 创建数据库连接 填入数据库信息
//填自己数据库的信息!!!!!!!!!!!
const conn = mysql.createConnection({user:'root', //用户名password:'admin123', //密码host:'localhost', //主机(默认都是local host)database:'node' //数据库名
})
// 测试连接
conn.connect(err=>{console.log(err,'如果为null 就是连接成功');
})
// 开启服务器
app.listen(3100,()=>{console.log('服务器在3000端口开启。。。。。');
})//3.测试mysql模块能否正常工作
// 调用db.query0函数,指定要执行的SQL语句,通过回调函数拿到执行的结果:
conn.query('select 1',(err,results)=>{if (err)return console.log(88,err.message)//只要能打印出[RowDataPacket《·1':1}】的结果,就证明数据库连接正常console.log(45,results)
})// 定义路由(说白了就是网址)
app.get('/add',(req,res)=>{// 向数据库 student 表里增加 name age 数据let sqlStr = "INSERT INTO student ( name, age )VALUES('小刚',4345)"//执行mysql 语句conn.query(sqlStr,(err)=>{console.log(err,'如果为null,sql语句执行成功')})//成功后的页面显示res.send('插入成功')
})// 查询信息
app.get('/find',(req,res)=>{let sql = `SELECT * FROM student `conn.query(sql,(err,results)=>{//返回的查询信息为result 然后将其显示在页面上res.send(results)})
})// 更换用户头像
app.get('/update',(req,res)=>{// 根据id 更新student 表里的 user_piclet sql = `update student set user_pic=? where id=?`conn.query(sql,[req.body.avatar,req.body.id],(req,sqlRes) => {// 执行 SQL 语句失败 if (err) return res.cc(err) // 执行 SQL 语句成功,但是影响行数不等于 1 if (sqlRes.affectedRows !== 1) return res.cc('更新头像失败!') // 更新用户头像成功 return res.cc('更新头像成功!', 0)})
})// 删除数据
app.get('/delete/:id', (req, res) => {let sql = `DELETE FROM student where id=?`conn.query(sql,[req.params.id], function (err, results) {if (err) return console.log(88, err.message)console.log(45, results)res.send({ mas: '删除成功', code: 200, data: results })})
})
相关文章:
node.js服务端笔记文档学会写接口,学习分类:path、包、模块化、fs、express、中间件、jwt、开发模式、cors。
node.js 学习笔记 node.js服务端笔记文档学会写接口,path、包、模块化、fs、express、中间件、JWT、开发模式、cors。 gitee:代码接口笔记 1什么是node.js nodejs 是基于ChromeV8,引擎的一个javaScript 运行环境。node.js 无法使用DOM和BO…...
初始C++(三):引用
文章目录一.引用的概念二.引用的使用1.引用作为输出型参数2. 引用作为函数返回值3.const引用三.引用的一些小问题四.引用和指针五.引用和指针的区别一.引用的概念 引用的作用是给一个已经存在的变量取别名,编译器不会为引用变量开空间,引用变量和被他引…...
【前端】参考C站动态发红包界面,高度还原布局和交互
最近有些小伙伴咨询博主说前端布局好难,其实都是熟能生巧! 模仿C站动态发红包界面,cssdiv实现布局,纯javascript实现交互效果 目录 1、界面效果 2、界面分析 2.1、整体结构 2.2、标题 2.3、表单 2.4、按钮 3、代码实现 3.…...
VR全景带你浪漫“狂飙”情人节,见证甜蜜心动
当情人节遇上VR,足以让情侣过一个难忘的情人节。马上情人节就要到了,大家是不是还在绞尽脑汁的想着,如何和另一半过一个浪漫的情人节呢?老套的剧情已经不能吸引人了,让我们看看VR全景给情人节带来了哪些不同的体验吧&a…...
Linux系统安全之iptables防火墙
目录 一.iptables防火墙基本介绍 二.iptables的四表五链 三.iptables的配置 1.iptables的安装 2.iptables防火墙的配置方法 四.添加、查看、删除规则 1.查看(fliter)表中的所有链 iptables -L 2.使用数字形式(fliter)表所有链 查看输出结果 iptables -nL 3.清空表中所…...
【C#基础】C# 变量与常量的使用
序号系列文章1【C#基础】C# 程序通用结构2【C#基础】C# 基础语法解析3【C#基础】C# 数据类型总结文章目录前言一. 变量(variable)1,变量定义及初始化2,变量的类别3,接收输出变量二. 常量(constantÿ…...
[ 常用工具篇 ] CobaltStrike(CS神器)基础(一) -- 安装及设置监听器详解
🍬 博主介绍 👨🎓 博主介绍:大家好,我是 _PowerShell ,很高兴认识大家~ ✨主攻领域:【渗透领域】【数据通信】 【通讯安全】 【web安全】【面试分析】 🎉点赞➕评论➕收藏 养成习…...
Redis集群
Redis集群 本章是基于CentOS7下的Redis集群教程,包括: 单机安装RedisRedis主从Redis分片集群 1.单机安装Redis 首先需要安装Redis所需要的依赖: yum install -y gcc tcl然后将课前资料提供的Redis安装包上传到虚拟机的任意目录ÿ…...
00---C++入门
1. C关键字(C98) C总计63个关键字,C语言32个关键字 2. 命名空间 在C/C中,变量、函数和后面要学到的类都是大量存在的,这些变量、函数和类的名称将都存在于全局作用域中,可能会导致很多冲突。使用命名空间的目的是对标识符的名称进…...
Spring-事务2
文章目录前言一、事务的特性(ACID)二、事务的隔离级别三、spring中的事务平台事务管理器.事务定义ISOLation_XXX:**事务隔离级别.**PROPAGATION_XXX:**事务的传播行为**.事务状态关系:四、使用XML文件配置事务1、 搭建…...
Windows Git Bash 配置
Windows Git Bash 配置 本文参考的文章: 在 Windows 的 Git Bash 中使用包管理器 - iris (ginshio.org)Git bash 安装 pacman & Windows 解压 zst 文件 | 伪斜杠青年 (lckiss.com) 一、Git的安装 Git 的安装应该是都会的,但还是应该说以下&#…...
java代码整合kettle9.3实现读取表中的数据,生成excel文件
java代码整合kettle9.3实现读取表中的数据,生成excel文件 1.简介 本次使用java代码整合kettle9.3版本,数据库使用mysql。 2.jar包导入 项目需要依赖部分kettle中的jar包,请将这部分jar包自行导入maven仓库。 <dependency><groupId…...
分享微信点餐小程序搭建步骤_微信点餐功能怎么做
线下餐饮实体店都开始摸索发展网上订餐服务。最多人选择的是入驻外卖平台,但抽成高,推广还要另买流量等问题,也让不少商家入不敷出。在这种情况下,建立自己的微信订餐小程序,做自己的私域流量是另一种捷径。那么&#…...
4、数组、切片、map、channel
目录一、数组二、切片三、map四、channel五、引用类型一、数组 数组: 数组是块连续的内存空间,在声明的时候必须指定长度,且长度不能改变所以数组在声明的时候就可以把内存空间分配好,并赋上默认值,即完成了初始化数组…...
270 uuid
270 uuid 用途 For the creation of RFC4122 UUIDs 可靠性 10000 星星 适应于浏览器或者服务器 官网链接 https://www.npmjs.com/package/uuid https://github.com/uuidjs/uuid 基本使用 import { v4 as uuidv4 } from uuid; uuidv4(); // ⇨ 9b1deb4d-3b7d-4bad-9bdd-2b0d7b3d…...
2023最新简历模板免费下载
下面分享5个简历模板网站,免费下载,建议收藏! 2023用最漂亮的简历模板,让面试官眼前一亮。 1、菜鸟图库 个人简历模板|WORD文档模板免费下载 - 菜鸟图库 菜鸟图库除了有超多设计类素材之外,还有很多办公类素材&#…...
【CSS】元素居中总结-水平居中、垂直居中、水平垂直居中
【CSS】元素居中一、 水平居中1.行内元素水平居中(1)text-align2.块级元素水平居中2.1 margin(1)margin2.2布局(1)flex justify-content(推荐)(2) flexmargin…...
spring实现AOP
文章目录前言一、AOP的底层实现原理二、AOP的两种开发模式1.使用xml配置文件1.1 添加AOP依赖1.2 创建UserService1.3创建UserServiceImpl1.4创建通知类1.5 创建applicationContext.xml(添加aop约束)1.6 测试2.使用注解开发2.1 创建bean.xml文件配置注解方…...
neovim搭建cpp环境
文章目录Windowns下NeoVim搭建cpp环境NeoVim安装插件vim-plugindentLinevim-airlinectagstagbarcoc.vimWindowns下NeoVim搭建cpp环境 在开发过程中习惯在DIE环境中使用vim作为编辑器,在单独的编辑器也常使用gvim图形化编辑器。最近看到NeoVim的特性及兼容性方面不输…...
SpringBoot AES加密 PKCS7Padding 模式
AES 简介:DES 全称为Data Encryption Standard,即数据加密标准,是一种使用密钥加密的块算法,1977年被美国联邦政府的国家标准局确定为联邦资料处理标准(FIPS) AES 密码学中的高级加密标准(Advan…...
按键输入驱动
目录 一、硬件原理 二、添加设备树 1、创建pinctrl 2、创建节点 3、检查 编译复制 三、修改工程模板编辑 四、驱动编写 1、添加keyio函数 2、添加调用 3、驱动出口函数添加释放 4、添加原子操作 5、添加两个宏定义 6、初始化原始变量 7、打开操作 8、读操作 总体代…...
2023年第七周总周结 | 开学倒数第三周
为什么要做周总结? 1.避免跳相似的坑 2.客观了解上周学习进度并反思,制定可完成的下周规划 一、上周问题解决情况 晚上熬夜导致第二天学习状态不好 这周熬夜一天,晚上帮亲戚修手机到22:30,可能是晚上自己的事什么都没做ÿ…...
Springboot扫描注解类
Springboot扫描注解类的入口在AbstractApplicationContext的refresh中,对启动步骤不太了解的,可参考https://blog.csdn.net/leadseczgw01/article/details/128930925BeanDefinitionRegistryPostProcessor接口有多个实现类,扫描Controller、Se…...
Apache日志分析器
您的Apache HTTP服务器生成的日志数据是信息的宝库。使用这些信息,您可以判断您服务器的使用情况、找出漏洞所在,并设法改进服务器结构和整体性能。审核您的Apache日志可在以下情况派上用场,其中包括:识别和纠正频繁出现的错误以增…...
啪,还敢抛出异常
🙉 作者简介: 全栈领域新星创作者 ;天天被业务折腾得死去活来的同时依然保有对各项技术热忱的追求,把分享变成一种习惯,再小的帆也能远航。 🏡 个人主页:xiezhr的个人主页 前言 去年又重新刷了…...
Apache JMeter 5.5 下载安装以及设置中文教程
Apache JMeter 5.5 下载安装以及设置中文教程JMeter下载Apache JMeter 5.5配置环境变量查看配置JDK配置JMeter环境变量运行JMeter配置中文版一次性永久设置正文JMeter 下载Apache JMeter 5.5 官方网站:Apache JMeter 官网 版本介绍: 版本中一个是Bina…...
string类模拟实现
了解过string常用接口后,接下来的任务就是模拟实现string类。 目录 VS下的string结构 默认成员函数和简单接口 string结构 c_str()、size()、capacity()、clear()、swap() 构造函数 拷贝构造函数 赋值重载 析构函数 访问及遍历 容量操作 reserve resize …...
cadence SPB17.4 S032 - allegro - 保存/载入光绘层定义
文章目录cadence SPB17.4 S032 - allegro - 保存/载入光绘层定义概述保存光绘层在新板子中载入已经保存的相同类型老板子定义好的光绘层定义文件碎碎念ENDcadence SPB17.4 S032 - allegro - 保存/载入光绘层定义 概述 以前布线完成, 准备出板厂文件时, 总是要手工重新建立光绘…...
微服务实战--高级篇:分布式缓存 Redis
分布式缓存 – 基于Redis集群解决单机Redis存在的问题 单机的Redis存在四大问题: 1.Redis持久化 Redis有两种持久化方案: RDB持久化AOF持久化 1.1.RDB持久化 RDB全称Redis Database Backup file(Redis数据备份文件)…...
【C语言】可变参数列表
本篇博客让我们来认识一下C语言学习过程中往往被忽略的可变参数列表 所谓可变参数,就是一个不限定参数数量的函数,我们可以往里面传入任意个数的参数,以达成某些目的。 关联:C11可变模板参数;本文首发于 慕雪的寒舍 …...
做外贸网站哪家效果好/怎么建网站免费的
原因:opencv3.0或者3.1的using namespace cv和windows.h中ACCESS_MASK定义冲突。 解决方案:注释掉所有的using namespace cv,然后在需要的地方写上cv::。 以后写C&opencv程序时,尽量不用using namespace 命名空间,以免产生命名…...
360帝国模板网欢迎大家来访_济南网站建设/推广_济南 去114网/seo营销怎么做
一 前言- 触目惊心的一组数据刚刚看了Symantec 赛门铁克公司三月份最新发布的互联网安全报告。有这么一组数据令人震惊。[1]北京市是全球感染Bot计算机数目最多的城市,占总感染量的5%中国是全球感染Bot计算机数目最多的国家或地区,占总感染量的26%美国…...
一个网站一年的费用/百度账号官网
求 $2^{2^{2^{2...}}}$ 即 $2^{2^\infty }$ 有扩展欧拉定理 : $2^{b} \equiv2^{b\%\varphi(x)\varphi(x)}$$(b\geq\varphi(x))$ 在这道题中,$b$ 始终为 $2^{2^{\infty}}$, 大小并不会减小. 好在 $\varphi(x)$ 的值会不断变小.递归出口为 $x1$,…...
有人上相亲网站做传销燕窝/站长聚集地
环境:DB:Oracle11.2.0.2OS:OEL Linux (OEL)5.6现象:更改hostnamenjdyw -> hotel07重启服务器后发现crs服务无法启动[oraclehotel07 diag]$ crs_stat -tCRS-0184: 无法与 CRS 守护程序通信。[oraclehotel07diag]$ crsctl start hasCLSU-00105: 操作系统…...
唐山网站建设互众动力/seo外包公司多少钱
个人原创,欢迎转载,转载请注明原文地址http://blog.csdn.net/bill_man从本篇文章开始,将分析cocos2D-X 3.0源代码,第一部分是从cocos2D-X学习OpenGL,也就是分析cocos2D-X 3.0的渲染代码,本篇首先介绍cocos2…...
深圳网站建设51duoshi/关联词有哪些四年级
课程结束了,老师要求我们每人写一篇关于软件工程课建议的博客,现在,我就这学期软件工程课程浅谈一下自己的感受: 1、软件工程课程对于我们来说是一个必备的课程,这一整个学期,我们都是以小团队的形式完成课…...