注意:整个node.js学习阶段,概念类知识点较多,需要理解透彻!
什么是 Node.js:就是 Javascript 的服务器端运行环境,可以让程序员使用 Javascript 来实现服务器端的编程;
是基于chorm的v8引擎的javascript运行环境,事件驱动,非阻塞I/O
node是后台语言,用javascript实现
Node.js 中 Javascript 的组成部分
注意:Node.js 中 没有 BOM 和 DOM
什么是 Node.js(我们自己给它下个定义)
就是一个服务器端的Javascript运行环境,可以让程序员,通过 Javascript 做 后台服务器编程开发
学习 Node.js 可以做什么
安装的 node中包含了npm
node -v
即可shift
键不松开,然后,在空白位置,鼠标右键单击,会出来一个右键菜单,选择在此处打开 powershell/cmd 窗口
windows徽标 + R
打开运行面板,输入 cmd
后直接回车;node 要执行的js文件的路径
来执行指定的JS文件小技巧:
- 在终端中,使用键盘的↑, 可以快速定位到上一次执行的命令
- 在终端中,使用键盘的
tab
键能够快速补全路径- windows 系统上,在终端中输入
cls
可以清屏
node
并回车,就会进入到 REPL 环境中;ctrl + c
就能退出 REPL 环境;vscode打开集成的终端 ctrl+反引号(tab上方的),用tab可以补全路径
{ }
作用域定义:所谓的解构赋值,就是把 某个对象中的属性,当作变量,给解放出来,这样,今后就能够当作变量直接使用了;
:
为解构出来的变量重命名 js
// 变量的解构赋值
let user={
name:'zs',
age:18,
gender:'女'
}
// 结构赋值的标准写法
//把user中的变量释放出来
let {name,age:userage,gender}=user;
console.log(name);
//起了别名之后不能再访问age,只能方位userage
语法:
定义普通的 function
函数
function show() {
console.log('这是普通 function 定义的 show 方法')
}
把方法定义为箭头函数(最完整的写法)
(形参列表) => { 函数体代码 }
() => {
console.log('这是普通 function 定义的 show 方法')
}
箭头函数,本质上就是一个匿名函数;
箭头函数的特性: 箭头函数内部的 this, 永远和 箭头函数外部的 this 保持一致;
document.getElementById('btn').onclick = function () {
setTimeout(function() {
this.style.backgroundColor = 'red';
}, 1000);
}//因为This的指向问题,此代码会报错
变体:
{ }
可以省略,同时rreturn也可以省略;()
和 {}
都可以省略注意: 如果我们省略了 右侧函数体的 { }
,那么,默认会把 右侧函数体中代码的执行结果,当作箭头函数的调用结果 return 出去;
var add = x => x+x
定义方法
和 定义属性
的便捷方式let name='zs';
let age = 13;
let show =() => {
console.log('show');
}
let person = {
name,
age,
show,
// see : function () {
// console.log('see');
// }
see() {
console.log('see');
}
}
console.log(person)
const fs = require('fs');
fs.readFile__dirname+'/files/2.txt','utf-8',(err,data)=>{
if(err) return console.log('文件读取失败'+err.message);
console.log('读取成功,文件的内容是'+data);
})
const fs = require('fs');
fs.writeFile(__dirname+'/files/2.txt','222你好',(err)=>{
if(err) return console.log('文件写入失败'+err.message);
console.log('文件写入成功');
})
const fs = require('fs');
fs.appendFile(__dirname+'/files/2.txt','\n444',(err)=>{
if(err) return console.log('追加失败'+err.message);
console.log('追加成功');
})
使用 fs 模块操作文件的时候,如果提供的操作路径是 相对路径
, 则会根据当前执行node命令时的磁盘目录,去拼接提供的文件的相对路径,从而容易出现问题;例如:
const fs = require('fs')
// 调用 fs.readFile 方法时,提供的第一个参数是相对路径,容易出现问题
fs.readFile('./files/1.txt', 'utf-8', (err, data) => {
if(err) return console.log(err.message)
console.log(data)
})
推荐使用 node 中提供的 __dirname
来解决 fs 模块操作文件时候的路径问题
fs.stat
fs.stat(__dirname+'/1.txt',(err,stats)=>{
if(err) return console.log('获取文件信息失败'+err.message);
console.log(stats.birthtime);
console.log(stats.size);
})
fs.readdir
fs.copyFile
const fs = require('fs');
fs.copyFile('./2.txt',__dirname+'/files/copy.txt',(err)=>{
if(err) return console.log('拷贝失败'+err.message);
console.log('拷贝成功')
})
成绩.txt
文件中的数据到成绩 - ok.txt
文件中,整理好的文件中,格式类似于:小红:99
小白:100
小黄:70
小黑:66
小绿:88
原来的格式:小红=99 小白=100 小黄=70 小黑=66 小绿=88
const fs = require('fs')
const path = require('path')
fs.readFile(path.join(__dirname,'/成绩.txt'),'utf-8',(err,data)=>{
if(err) return console.log('读取文件失败'+err.message)
// console.log(data)
let newStr = data.split(' ')
// console.log(newStr)
let newData = []
newStr.forEach(item=>{
if(item.length>0){
// console.log(item)
let newScore = item.replace('=',':')
//console.log(newScore)
newData.push(newScore)
}
})
// console.log(newData)
fs.writeFile(path.join(__dirname,'/成绩-ok.txt'),newData.join('\n'),err=>{
if(err) return console.log('写入失败')
console.log('写入成功')
})
})
http
模块的基本使用Javascript 的解析和执行一直是单线程的,但是宿主环境(浏览器或node)是多线程的;
异步任务(ajax,定时器等耗时的任务)是由宿主环境开启子线程完成,并通过事件驱动、回调函数、队列,把完成的任务, 交给主线程执行;
所有的一部任务都是由浏览器执行的
Javascript解析引擎,一直在做一个工作,就是从任务队列里提取任务,放到主线程里执行。
事件队列中任务执行的条件:1)主线程已经空闲
2)任务满足触发条件:定时函数(延时时间已经达到),事件函数(事件被触发),ajax回调函数(服务器端数据被响应)
模块化就是一种约定,一定规范;
场景模拟:小强,小黄,小刚 共同基于 Node.js 开发项目!
在Node.js中有两个作用域,分别是 全局作用域 和 模块作用域;
global
来访问,类似于浏览器中的window
;global.***
来挂载;global
全局作用域来共享成员,会存在全局变量污染问题;module(模块标识)
module 属性是 Common JS 规范中定义的,它是一个对象,表示当前这个具体的 js 模块;
require(引用模块)
每一个实现了 CommonJS 规范的模块,必须定义一个 require() 函数,使用这个 require 函数,就能够 很方便的导入其它 模块中的成员,供自己使用;
exports(暴露模块成员)
每一个模块中,如果想要把自己的一些私有成员,暴露给别人使用,那么,必须实现一个 exports 对象,通过exports对象,可以方便的把模块内私有的成员,暴露给外界使用;
module.exports
和 exports
默认引用了同一个空对象,指向地址相同;module.exports
和 exports
作用一致,都可以向外暴露成员;module.exports
为准,开发中推荐使用,画内存图理解;注意:浏览器端不能使用 CommonJS规范;因为 CommonJS 下,模块是同步加载的;
AMD/CMD可以理解为是commonjs在浏览器端的解决方案,AMD/CMD下,模块都是异步加载的;
模块
和 包
的概念回顾:Node.js 由三部分组成:ECMAScript 核心 + 全局成员 + 模块成员
模块成员,根据一些区别,又可以分为三大类: 核心模块、第三方模块、用户自定义模块
fs
,path
等模块,都是由Node.js官方提供的核心模块;require('核心模块标识符')
NPM
的网站上搜索并下载才能使用;require('第三方模块的名称标识符')
来导入这个模块require('路径标识符')
Packages
,包是在模块基础上更深一步的抽象;package.json
必须在包的顶层目录下;package.json
文件必须符合 JSON 格式,并且必须包含如下三个属性:name
, version
, main
package.json
,并符合基本规范即可;name:包的名称,必须是唯一
description:包的简要说明
version:符合语义化版本识别规范的版本字符串
keywords:关键字数据,通常用于搜索
maintainers:维护者数组,每个元素要包含name、email、web可选字段
contributors:贡献者数组,格式与maintainers相同。包的坐着应该是贡献者数据的第一个元素
bugs:提交bug的地址,可以是网址或者电子邮件地址
licenses:许可证数组,每个元素要包含type和url字段
repositories:仓库托管地址数组,每个元素要包含type、url和path字段
dependencies:包的依赖,一个关联数组,由包名称和版本号组成。
devDependencies:开发依赖项,表示一个包在开发期间用到的依赖项
https://www.npmjs.com/
;npm install 包名 -g
即可;其中 -g
参数,表示 把包安装到全局目录中的意思;C:\Users\用户目录\AppData\Roaming\npm
npm uninstall 包名 -g
即可;其中 uninstall
表示卸载的意思;npm init
或者npm init -y
命令,初始化一个package.json
的配置文件,否则包无法安装到本地项目中;npm i 包名 --save
即可安装本地包;都安装到了当前项目的 node_modules
目录下; --save
命令,如果用的是 npm 3.x 的版本,则需要手动指定 --save
;package-lock.json
文件中记录了曾经装过的包的下载地址,方便下次直接下载包,能够加快装包的速度,提升装包的体验;npm uninstall/remove 包名 -S/-D
即可卸载指定的本地包;--save
的缩写是 -S
开发阶段和上线阶段都会用--save-dev
的缩写是 -D
开发阶段使用,上线之后不需要使用,在devdependence节点下install
的缩写是 i
dependencies
节点,表示项目上线部署时候需要的依赖项;devDependencies
节点,表示项目在开发阶段需要的依赖项,但是当项目要部署上线了,devDependencies
节点中的包,就不再需要了!npm i
快速装包的时候,npm会检查package.json
文件中,所有的依赖项,然后都为我们安装到项目中--production
表示只安装 dependencies
节点下,记录的包,不安装devDependencies
节点下的包;当项目要上线了,才会使用--production
命令cnpm
cnpm
:运行 npm i cnpm -g
即可;cnpm
:在装包的时候,只需要把 npm
替换成 cnpm
即可,例如: npm
安装 jquery
:运行 npm i jquery -S
cnpm
安装 jquery
: 运行 cnpm i jquery -S
什么是B/S:特指基于 浏览器(Browser) 和 服务器(Server) 这种交互形式;
请求 - 处理 - 响应
的过程; 使用
http
核心模块,创建最基本的web服务器
创建最基本的web服务器
const server = http.createServer()
创建服务器;server.on('request', function(req, res) { 请求的处理函数 })
绑定事件 并 指定 处理函数;server.listen(端口, IP地址, 启动成功的回调函数)
来启动服务器;//引入http模块
const http = require('http');
//创建服务器
const server = http.createServer();
//绑定监听事件
server.on('request',function (req,res) {
res.writeHeader(200,{
'Content-Type':'text/plain;charset=utf-8'
})
res.end('你好');
})
//启动服务器
server.listen(3000,'127.0.0.1',function () {
console.log('server running at http://127.0.0.1:3000');
})
防止响应内容中文乱码问题
通过 设置响应报文头的 Content-Type
,来指定响应内容的编码类型,从而防止乱码:
res.writeHeader(200, {
'Content-Type': 'text/plain; charset=utf-8'
//浏览器默认编码为gbk,此处设置text/plain表示普通文本,charset=utf-8表示以utf-8的形式进行编码
})
需要在res.end()之前来设置
根据不同的URL返回不同的文本内容
req.url
获取客户端请求的URL地址根据不同的URL返回不同的HTML页面
fs 模块
读取URL对应的HTML页面内容,并使用 res.end()
响应给客户端即可;text/plain 表示普通文本字符串
text/html 表示以html标签的形式解析文本
处理并返回css样式表
处理并返回Javascript文件
优化
const http = require('http');
const fs = require('fs');
const path = require('path');
const server = http.createServer();
server.on('request',(req,res)=>{
// res.writeHeader(200,{
// 'Content-Type':'text/html;charset=utf-8'
// })在html页面中已经设置了编码格式
let url = req.url;
if(url==='/') url = '/view/index.html';
fs.readFile(path.join(__dirname,url),(err,buf)=>{
if(err) return res.end('404,not found');
res.end(buf);
//buf表示二进制,能用二进制就不用string,因为在传递的数据时始终以二进制形式传递,用buf少了一层转化
})
})
server.listen(3000,'127.0.0.1',function () {
console.log('server running at http://127.0.0.1:3000');
})
<h2>这是一个动态渲染的页面 h2>
<p>name:{
{name}}p>
<p>gender:{
{gender}}p>
<p>
{
{each hobby}}
{
{$value}}
{
{/each}}
p>
const http = require('http');
const template = require('art-template');
const path = require('path');
const server = http.createServer();
server.on('request',(req,res)=>{
let url = req.url;
if(url==='/'){
const htmlStr = template(path.join(__dirname,'/view/1.html'),{name:'zs',gender:'女',hobby:['唱歌','跳舞']});
res.end(htmlStr);
}
})
server.listen(3000,'127.0.0.1',()=>{
console.log('server running at http://127.0.0.1:3000');
})
calc
计算器包,并尝试向 calc
包中,添加 mod 求余数的方法类似于Apache的静态资源服务器
nodemon
工具来自动重启web服务器npm i nodemon -g
全局安装即可;node 要执行的文件路径
来运行 Node.js 代码;nodemon 要执行的文件路径
来运行 Node.js 代码;nodemon
来启动 web 服务器定义(什么是Express):一个快速的网站开发框架,封装了原生的http模块,用起来更方便;API更人性化
http
模块,从而提供了更好用,更友好的 APInpm i express -S
即可安装express
服务器: express
第三方模块;const app = express()
方法;app.get()
或 app.post()
方法,来监听客户端的 get
或 post
请求,具体语法: GET
请求:app.get('请求地址', (req, res) => { 处理函数 })
POST
请求: app.post('请求地址', (req, res) => { 处理函数 })
app.listen(端口, IP地址, 启动成功后的回调函数)
启动服务器;//导入express模块
const express = require('express');
//创建服务器
const app = express();
//监听路径
app.get('/',(req,res)=>{
res.send('ok你好吗');
})
//开启服务器
app.listen(3000,'127.0.0.1',()=>{
console.log('server running at http://127.0.0.1:3000');
})
//说明:express主要封装了http模块,使得创建服务器更加便捷
res.send()
Content-Type: text/html;
Content-Type: application/json
res.sendFile()
res.sendFile(path.join(__dirname, './view/index.html'))
res.sendFile('./view/movie.html', { root: __dirname })
res.sendFile()
可以向浏览器发送 静态页面;express.static()
快速托管静态资源如果我们网站中,有很多静态资源需要被外界访问,此时,使用 res.sendFile 就有点力不从心了;
这时候,express 框架,为我们提供了
express.static('静态资源目录')
来快速托管指定目录下的所有静态资源文件;
语法1: app.use(express.static('public'));
app.use()
方法,是专门用来注册 中间件;express.static
是express的内置中间件;const express = require('express');
const app = express();
//指定目录下的所有文件都可以直接被浏览器访问
app.use(express.static('./view'));
app.listen(3000,'127.0.0.1',()=>{
console.log('http://127.0.0.1:3000')
})
语法2:app.use('/虚拟目录', express.static('public'))
npm i ejs -S
app.set('view engine', 'ejs')
app.set('views', './views')
res.render('index.ejs', { 要渲染的数据对象 })
,注意,模板页面的 后缀名,可以省略不写!注:用ejs渲染的页面后缀名只能叫.ejs
const express = require('express')
const app = express()
//1.使用app.set()配置默认的模板引擎
app.set('view engine','ejs')
//2.配置模板页面的存放路径
app.set('views','./ejs-page')
app.get('/',(req,res)=>{
//3.使用render函数渲染页面
res.render('index.ejs',{name:'zs',gender:'女',hobby:['唱歌,跳舞,打游戏']})
})
app.listen(3000,'127.0.0.1',()=>{
console.log('http://127.0.0.1:3000')
})
<body>
<h1>这是用ejs渲染的页面h1>
<p><%= name%>p>
<p><%= gender%>p>
<%hobby.forEach(item=>{%>
<%= item%>
<%})%>
body>
cnpm i art-template express-art-template -S
app.engine('自定义模板引擎的名称', 渲染函数)
注意:此处模板引擎的名字一定是要渲染页面 的后缀名
app.set('view engine', '具体模板引擎的名称')
app.set('views', '路径')
<body>
<h1>这是使用 art-template 渲染的模板页面h1>
<p>姓名:{
{name}}p>
<p>年龄:{
{age}}p>
{
{each hobby}}
<p>{
{$index}} -- {
{$value}}p>
{
{/each}}
body>
const express = require('express')
const app = express()
// 1. 使用 app.engine() 方法自定义模板引擎
app.engine('html', require('express-art-template'))
// 2. 使用 app.set('view engine', '指定模板引擎名称') 来配置项目中用到的模板引擎
app.set('view engine', 'html')
// 3. 配置模板页面的存放路径
app.set('views', './art_page')
app.get('/', (req, res) => {
res.render('index.html', { name: 'zs', age: 22, hobby: ['玩游戏', '唱歌'] })
})
app.listen(3000, () => {
console.log('server running at http://127.0.0.1:3000')
})
const express = require('express')
const app = express()
//引入路由模块
const router = require('./router.js')
//使用app.use()注册路由
app.use(router)
app.listen(3000,'127.0.0.1',()=>{
console.log('http://127.0.0.1:3000')
})
//这里是路由模块
const express = require('express')
//通过express.Router()得到一个路由对象
const router = express.Router();
//将路由规则挂载到router对象上
router.get('/',(req,res)=>{
res.sendFile('./view/index.html',{root:__dirname})
})
router.get('/about',(req,res)=>{
res.sendFile('./view/about.html',{root:__dirname})
})
//将路由对象暴露出去供外界使用
module.exports = router
// 1. 封装单独的 router.js 路由模块文件
const express = require('express')
// 创建路由对象
const router = express.Router()
router.get('/', (req, res)=>{})
router.get('/movie', (req, res)=>{})
router.get('/about', (req, res)=>{})
// 导出路由对象
module.exports = router
// 导入自己的路由模块
const router = require('./router.js')
// 使用 app.use() 来注册路由
app.use(router)
在应用程序开发中每一个处理环节都是一个中间件,中间件之间要共享数据,中间件之间要有先后的调用顺序,数据如果想要从上一个中间件流转到下一个中间件,必须调用相关的方法才可以
定义:中间件就是一个处理函数;只不过这个函数比较特殊,包含了三个参数,分别是
req
,res
,next
中间件中间共享的是req和res,调用下一个中间件时用的是next()
注意:中间件方法中的三个参数:
- req:请求对象;
- res:响应对象;
- next:next()可以被调用,表示调用下一个中间件方法;
app.get('URL地址', (req, res, next)=> {})
;绑定到app对象上的router.get('url地址', (req, res, next)=>{})
绑定到router上的app.use((err, req, res, next)=>{})
express.static()
body-parser
解析post 表单数据中间件的概念,了解即可,因为实际开发中,我们都直接使用第三方现成的中间件;
// 导入 express 模块
const express = require('express')
const querystring = require('querystring')
// 创建 express 的服务器实例
const app = express()
// 定义 应用级别的中间件
app.use((req, res, next) => {
let dataStr = ''
// 只要客户端向服务器提交了表单,都会触发 req 的 data 事件
// 在 data 事件中,可以获取到客户端每次提交过来的,不完整的数据,每次发过来的数据都是chunk
req.on('data', chunk => {
dataStr += chunk
})
// 只要 req 触发了 end 事件,就表示表单数据,提交完毕了,dataStr 中存储的数据,就是完整的表单数据
req.on('end', () => {
console.log(dataStr)
const obj = querystring.parse(dataStr)
// querystring.parse可以把按照&,=分割的字符串解析成对象
//想要把 username=ls&password=123 字符串,解析为 { username: 'ls', password: 123 }
console.log(obj)
req.body = obj//把从客户端解析的数据挂载到req上,req,res在各个中间件之间共享
// 进入下一个中间件的处理环节;
// 注意:在中间件中,最后,一定要合理的调用一下 next() 方法,否则,服务器 无法结束这次响应!
next()
})
})
// 这是应用级别的中间件
app.get('/', (req, res) => {
res.sendFile('./11.index.html', { root: __dirname })
})
app.post('/postdata', (req, res) => {
console.log(req.body)
// 需求:如何从客户端提交的表单中,获取到 客户端提交过来的数据呢?
res.send(req.body)
})
// 调用 app.listen 方法,指定端口号并启动web服务器
app.listen(3001, function() {
console.log('Express server running at http://127.0.0.1:3001')
})
<body>
<h3>演示中间件 表单 Post 提交数据h3>
<form action="/postdata" method="POST">
<p>用户名:
<input type="text" name="username">
p>
<p>密码:
<input type="password" name="password">
p>
<input type="submit" value="提交">
form>
body>
const express = require('express')
const app = express()
const mysql = require('mysql')
var con = mysql.createConnection({
host: 'localhost',
user: 'root',
password: '',
database: '0907'
});
con.connect();
app.get('/',(req,res)=>{
//--------------新增------------
const data = {username:'修改前',password:'18814072922'}
//此数据库插入数据的语法仅在node中适用,其他语言中语法不同
//?表示要传的参数,如果有两个参数,传递时用数组
con.query('insert into user set ?',data,(err,result)=>{
if(err) return console.log('数据插入失败'+err.message)
console.log('数据插入成功')
})
//--------------修改------------
const newData = {username:'修改后',password:'18834072922'}
con.query('update user set ? where username=?',[newData,'修改前'],(err,result)=>{
if(err) return console.log('修改数据失败'+err.message)
console.log('数据修改成功')
})
//--------------查询-------------
con.query('SELECT * from user', function (error, result) {
if(error) return console.log('获取数据失败'+error.message)
res.send(result)
});
//--------------删除-------------
con.query('delete from user where username=?','修改后',(err,result)=>{
if(err) return console.log('删除失败'+err.message)
console.log('数据删除成功')
})
})
app.listen(3000,'127.0.0.1',()=>{
console.log('http://127.0.0.1:3000')
})
require
的时候,会执行模块中的代码,当第二次加载相同模块的时候,会优先从缓存中查找,看有没有这样的一个模块!先查找缓存;
如果缓存中没有则尝试加载用户模块;
如果在加载用户模块时候省略了后缀名,则:
首先,严格按照指定的名称去查找
其次,尝试加载后缀名是 .js 的文件
如果没有.js的文件,则尝试加载 .json 结尾的文件
如果没有 .json 的文件,则尝试加载 .node 结尾的文件
查找规则:index -> index.js -> index.json -> index.node
node_modules
文件夹node_modules
文件夹下,查找模块相关的文件夹package.json
的文件package.json
文件中的main
属性(指定了模块的入口文件)main
属性,同时,main
属性指定的文件路径存在,那么尝试加载指定的文件模块main
属性,或者main
属性对应的文件不存在,或者没有package.json
,那么会依次尝试加载index.js
,index.json
,index.node
;index
相关的文件,或者没有指定模块对应文件夹,或者,当前项目根目录中没有node_modules
文件夹,则向上一层目录中查找node_modules
,查找规则同上!cannot find module ***
express.static
把 今天 资料
文件夹下,vue-cms
项目,托管成静态资源服务器;express
中,配置和使用 ejs/art-template
来渲染一个动态页面;index.html
, movie.html
, about.html
;分别使用三种方式,显示这三个静态页面; app
上;router
上;router.js
模块中,再抽离出 一个 handler.js
模块;art-template 官方文档
http://127.0.0.1:3001/user?id=10&name=zs
中的查询参数: req.query
获取参数即可;查询字符串
传递的参数,express 框架会直接解析,大家只需要使用 req.query
直接获取 URL 中 查询字符串的参数;app.get('/user/:id/:name', (req, res) => {})
(此处冒号表示参数项)http://127.0.0.1:3001/user/10/zs
req.params
可以获取URL地址中传递过来的参数;body-parser
来解析表单数据npm i body-parser -S
const bodyParser = require('body-parser')
app.use(bodyParser.urlencoded({ extended: false }))
req.body
来访问解析出来的数据前后端分离开发模式的注意点:
JSONP的原理:动态创建script标签;
CORS中文意思是跨域资源共享
,需要服务器端进行 CORS
配置;
对于Node来说,如果想要开启 CORS 跨域通信,只需要安装cors
的模块即可;
字段名 | 字段类型 | 字段描述 |
---|---|---|
id | int | 主键Id(自增) |
name | varchar | 英雄名称 |
gender | varchar | 性别 |
ctime | varchar | 创建时间 |
isdel | tinyint(布尔值) | 是否被删除 0 表示未删除;1 表示已经被删除 |
在 mysql 中的 tinyint 等同于 bool 值
http://127.0.0.1:5001/getallhero
http://127.0.0.1:5001/addhero
请求类型:GET
请求地址:http://127.0.0.1:5001/gethero/:id
请求参数:通过 URL 地址,把要查询的英雄Id,携带过去
请求类型: POST
请求地址:http://127.0.0.1:5001/updatehero/:id
请求参数:{ name, gender }
请求类型:GET
请求地址:http://127.0.0.1:5001/deletehero/:id
请求参数:通过 URL 地址栏传参,把 要删除的英雄Id提交给服务器
主要目标1:在渲染首页的时候,把相关的配置搭建起来(模板引擎、静态文件托管)
请求 - 处理 - 响应
的!cookie
,这样,每次发送请求,都会把这个cookie随同其他报文一起发送给服务器,服务器可以根据报文中的cookie,区分不同的客户端浏览器。如何在客户端请求头中添加标识符?
在Node中可以在writeHeader
的时候,通过Set-Cookie
来将cookie标识通过响应报文发送给客户端!
jquery.cookie
这个插件!var http = require('http');
var server = http.createServer();
server.on('request', function (req, res) {
// 解析cookie
var cookies = {};
var cookieStr = req.headers.cookie; // 从请求的headers中获取cookie信息
cookieStr && cookieStr.split(';').forEach(function (item) {
var parts = item.split('=');
cookies[parts[0].trim()] = parts[1].trim(); // 将cookie解析出来,保存到对象中
});
res.writeHeader(200, {
'Content-Type': 'text/plain; charset=utf-8',
"Set-Cookie": ['issend=ok', 'age=20']
});
if(cookies.issend ==='ok'){
res.end('不要太贪心哦!');
}else{
res.end('呐,赏你一朵小红花~~');
}
});
server.listen(4000, function () {
console.log('服务器已启动!');
});
expires
设置Cookie的过期时间// 设置 过期时间 为60秒之后
// 注意:在设置过期时间的时候,需要将时间转换为 UTC 格式
var expiresTime = new Date(Date.now() + 1000 * 60).toUTCString();
res.writeHeader(200, {
'Content-Type': 'text/html; charset=utf-8',
'Set-Cookie': ['isvisit=true;expires=' + expiresTime, 'test=OK']
});
res.end('你好,欢迎光临,送给你一个苹果!
');
GMT和UTC有什么区别?格林尼治标准时(GMT)与世界时(UTC)是怎么回事
使用谷歌插件edit this cookie
,就能伪造cookie数据!所以不要使用cookie存储敏感的数据!比如登录状态和登录信息;
一些敏感的数据,应该存储都服务器端!
express-session
来保存登录状态由于HTTP是无状态的,所以服务器在每次连接中持续保存客户端的私有数据,此时需要结合cookie技术,通过session会话机制,在服务器端保存每个HTTP请求的私有数据;
在服务器内存中开辟一块地址空间,专门存放每个客户端私有的数据,每个客户端根据cookie中保存的私有sessionId,可以获取到独属于自己的session数据。
使用流程:先在app.js安装注册express-session,然后在服务器端能访问到req对象的对应的函数时为session挂载属性(user,islogin),然后在contoll中的index.js渲染首页的时候把挂载的属性传递过来,同时在index.ejs中用ejs模板语法控制按钮组的现实
npm install express-session -S
var session = require('express-session')
session
中间件:// 启用 session 中间件,只要注册了中间件。之后凡是能访问到req,必然就能访问到req,session
app.use(session({
secret: 'keyboard cat', // 相当于是一个加密密钥,值可以是任意字符串
resave: false, // 强制session保存到session store中
saveUninitialized: false // 强制没有“初始化”的session保存到storage中
}))
// 将登录的用户保存到session中
req.session.user = result.dataValues;
// 设置是否登录为true
req.session.islogin = true;
destroy()
方法清空session
数据:req.session.destroy(function(err){
if(err) throw err;
console.log('用户退出成功!');
// 实现服务器端的跳转,这个对比于 客户端跳转
res.redirect('/');
});
req.session.destroy(()=>{
//使用redirect方法让客户端重新访问首页
res.redirect('/')
})
彩虹表
;bcrypt
加密算法,得到加密之后的密文进行存储;幂次
;$版本号$循环的幂次$22位的随机盐 31位的密文
随机盐
和加密的幂次
,和加密算法的版本号
已经被存储到了真正的密文中;运行 npm i node-pre-gyp -g
在项目根目录中,打开终端,运行 cnpm install bcrypt -S
导入 bcrypt
// 导入加密的模块
const bcrypt = require('bcrypt')
定义幂次:
// 定义一个 幂次
const saltRounds = 10 // 2^10
调用 bcrypt.hash()
加密:
// 加密的方法
bcrypt.hash('需要加密的密码', saltRounds, (err, pwdCryped) => {
console.log(pwdCryped)
要在此方法中写数据库的操作,否则不起作用
})
调用bcrypt.compare()
对比密码是否正确:
// 对比 密码的方法
bcrypt.compare('123', '$2b$10$i1ufUKnC9fXTsF9oqqvLMeDnpNfYIvhyqKRG03adiebNFPkjW3HPW', function(err, res) {
console.log(err)
// 内部对比的过程:
// 1. 先获取 输入的明文
// 2. 获取输入的密文
// 2.1 从密文中,解析出来 bcrypt 算法的 版本号
// 2.2 从密文中,解析出来 幂次
// 2.3 从密文中,解析出来前 22 位 这个随机盐
// 3. compare 方法内部,调用 类似于 hash 方法 把 明文,幂次,随机盐 都传递进去 最终得到正向加密后的密文
// 4. 根据最新得到的密文,和 compare 提供的密文进行对比,如果相等,则 返回 true ,否则返回 false;
})
在PHP中,抽取公共的区域,直接使用PHP语法就行;
但是,在Express的框架中,并没有抽取页面公共部分的语法,需要模板引擎提供这样的语法;
markdown + editor
=> mditor
注意:mditor
这个第三方模块,提供了两个功能:
require('mditor')
,使用这个模块,提供的方法,把markdown
文本,解析转换为HTML
内容;把markdown文本转化成html
1.安装marked
2.导入
3。调用marked marked(要转化的文本)