get和post请求的区别
- 作用
- GET主要用来请求数据,POST 主要用来提交数据
- 参数的位置
- GET带参数请求是将参数缀到URL之后 POST将参数放到请求体里面
- 安全性
- POST请求相对安全,因为在浏览器中参数会暴露在地址栏
- GET请求大小有限制,一般为2k,而post请求没有大小限制
模块化
将复杂的程序文件根据一定的规则拆分成多个文件的过程
每一个文件就是一个模块,模块内部数据私有,不过可以暴露给其他数据使用
防止命名冲突 高复用性
express中间件
使用函数封装公共操作,简化代码
- 全局中间件
- 路由中间件
app.use(express.static('./public')) //该目录存在一些静态资源
//访问内容经常变化,还是需要设置路由
//如果public目录下有index.html文件,单独也有index.html的路由
//谁写在前面优先执行谁
express框架快速入门
- 安装
使用npm init
命令为您的应用程序创建一个package.json
文件。
npm init
- 此命令会提示您输入许多信息,例如应用程序的名称和版本。现在,您只需点击 RETURN 即可接受其中大多数的默认值,但以下情况除外:
entry point: (index.js)
- 输入
app.js
,或任何您想要的主文件名称。如果您希望它是index.js
,请按 RETURN 以接受建议的默认文件名。 - ejs的安装(或者)
npm install ejs --save-d
- 最后安装依赖
npm install express
Express 生成器
-
对于较早的 Node 版本,将应用程序生成器安装为全局 npm 包,然后启动它:
npm install -g express-generator
-
添加ejs的模板引擎的支持
express -e -15generator
lowdb
npm install lowdb@1.0.0
// 导入lowdb
const low = require('lowdb')
const FileSync = require('lowdb/adapters/FileSync')
const adapter = new FileSync('db.json')
// 获取db对象
const db = low(adapter)
// 初始化数据
db.defaults({ posts: [], user: {} }).write()
// 写入数据
db.get('posts').unshift({id:666,title:"其实还挺简单的"}).write()
// // 获取数据
console.log(db.get('posts').value());
// 获取单条数据
let res = db.get('posts').find({id:666}).value()
console.log(res);
// 更新数据
let res = db.get('posts').find({id:666}).assign({title:'其实还挺难的'}).write()
console.log(res);
// 移除数据
let res = db.get('posts').remove({id:1}).write()
console.log(res);
shortid
npm install shortid
const shortid = require('shortid')
let id = generate()
文件上传
- 比body-parse功能更加强大
const formidable = require('formidable')
// 创建form表单对象
const form = new formidable.IncomingForm({
// 设置上传文件的保存目录
uploadDir:__dirname+'/../public/images',
// 保持文件后缀
keepExtensions:true
});
// 解析请求报文
form.parse(req, (err, fields, files) => {
if (err) {
next(err);
return;
}
console.log(fields);
console.log(files);
// res.json({ fields, files });
let url = '/images/'+ files.portrait[0].newFilename //将来保存在数据库中
res.send(url)
mongodb数据库
//避免promise处理文件操作
//npm install mongoose@4.13.0
// 导入mongoose
const mongoose = require('mongoose')
// 连接mongodb服务
mongoose.connect('mongodb://127.0.0.1:27017/demon')
// 设置回调
mongoose.connection.once('open',()=>{
console.log("连接成功");
// 创建文档的结构对象
// 设置集合中 文档的属性以及属性值的类型
let BookSchema = new mongoose.Schema({
name:String,
author:String,
price:Number
})
// 创建模型对象 对文档操作的封装对象 books:需要操作的集合名称 BookSchema:结构对象
let BookModel = mongoose.model('books',BookSchema);
// 新增
BookModel.create({
name:'西游记',
author:'吴承恩',
price:19.9
},(err,data)=>{
// 判断是否有错误
if(err){
console.log(err);
return
}
// 如果没有出错,则输出插入后的文本对象
console.log(data);
// 关闭数据库连接
mongoose.disconnect()
})
})
mongoose.connection.on('error',()=>{
console.log("连接失败");
})
mongoose.connection.on('close',()=>{
console.log("连接关闭");
})
关闭mongodb的连接服务
setTimeout(()=>{
mongoose.disconnect();
},2000)
//最新版的mongoose,使用Promise来处理插入文档的操作
BookModel.create({
name: '西游记',
author: '吴承恩',
price: 19.9
})
.then(data => {
console.log(data);
})
.catch(err => {
console.error(err);
});
字段校验
Mongoose有一些内建验证器,可以对字段进行验证
- 必选项 required
- 默认值 default
- 枚举值 enum
- 唯一值 unique ( unique 需要重建集合才能有效果 永远不要相信用户的输入)
文档操作
-
删除
- 一条deleteOne({},(err,data)=>{})
- 多条deleteMany({},(err,data)=>{})
-
更新
- 一条updateone({},{}(err,data)=>{})
- 多条updateMany({},{}(err,data)=>{})
-
读取
- 一条findOne({},(err,data)=>{})
- 一条findById({},(err,data)=>{})
- 多条find({},(err,data)=>{})
条件控制
-
运算符 在mongodb不能 > < >= <= !== 等运算符,需要使用替代符号
- > 使用 $gt
- < 使用 $lt
- >= 使用 $gte
- <= 使用 $lte
- !== 使用 $ne
-
逻辑运算
-
$or 逻辑或的情况
db.students.find({$or:[{age:18},{age:24}]});
-
$and 逻辑与的情况
```js
db.students.find({$and: [{age: {$lt:20}}, {age: {$gt: 15}}]})
```
-
正则匹配 条件中可以直接使用 JS 的正则语法,通过正则可以进行模糊查询
db.students.find({name:/imissyou/}) db.students.find({name:new RegExp('imissyou')})
个性化读取
-
字段筛选
//0:不要的字段 //1:要的字段 SongModel.find().select({_id:0,title:1}).exec(function(err,data){ if(err) throw err; console.log(data); mongoose.connection.close(); })
-
数据排序
//sort 排序
//1:升序
//-1:倒序
SongModel.find().sort({hot:1}).exec(function(err,data){
if(err) throw err;
console.log(data);
mongoose.connection.close();
});
-
数据截取
//skip 跳过 limit 限定 SongModel.find().skip(10).limit(10).exec(function(err,data){ if(err) throw err; console.log(data); mongoose.connection.close(); });
json-server
本身是一个js编写的工具包,可以快速搭建restfulApi服务
//全局安装
npm i -g json-serverd
//文件启动
json-server --watch db.json
API接口
var express = require('express');
var router = express.Router();
const shortid = require('shortid')
// 导入moment
const moment = require('moment')
const AccountModel = require('../../models/AccountModel')
// console.log(moment('2023-02-24').toDate());
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index', { title: 'Express' });
});
// 记账本的列表
router.get('/account', function(req, res, next) {
AccountModel.find().sort({time:-1}).exec((err,data)=>{
if(err){
res.json({
code:'1001',
msg:'读取失败~~',
data:null
})
}
res.json({
// 响应编号
code: '0000',
// 响应信息
msg: '读取成功',
// 响应的数据
data: data
})
})
});
// 新增记录
router.post('/account',(req,res)=>{
// let id = shortid.generate();
// // 获取请求体的数据
// console.log(req.body);
// // 写入文件
// db.get('accounts').unshift({id:id, ...req.body}).write()
AccountModel.create({
...req.body,
time:moment(req.body.time).toDate()
},(err,data)=>{
if(err){
res.json({
code:'1002',
msg:'创建失败~~~',
data:null
})
}
res.json({
code:'0000',
msg:'创建成功',
data:data
})
})
})
// 删除记录
router.delete('/account/:id',(req,res)=>{
let id = req.params.id
AccountModel.deleteOne({_id: id},(err,data)=>{
if (err) {
res.json({
code:'1003',
msg:'删除账单失败',
data:null
})
return
}
res.json({
code:'0000',
msg:'删除成功',
data:data
})
})
})
// 获取单个信息
router.get('/account/:id',(req,res)=>{
// 获取id参数
let {id} = req.params
// 查询数据库
AccountModel.findById(id,(err,data) =>{
if(err){
return res.json({
code:'1004',
msg:'查询错误',
data:null
})
}
res.json({
code:'0000',
msg:'获取成功',
data:data
})
})
})
//更新单个账号信息
router.patch('/account/:id',(req,res)=>{
let { id } = req.params
AccountModel.updateOne({ _id: id},req.body,(err,data)=>{
if(err){
return res.json({
code:'1005',
msg:'更新错误',
data:null
})
}
AccountModel.findById(id,(err,data)=>{
if(err){
return res.json({
code:'1004',
msg:'读取错误',
data:null
})
}
res.json({
code:'0000',
msg:'更新成功',
data:data
})
})
})
})
module.exports = router;
cookie会话控制
npm install cookie-parser
session会话控制
const express = require('express');
//1. 安装包 npm i express-session connect-mongo
//2. 引入 express-session connect-mongo
const session = require("express-session");
const MongoStore = require('connect-mongo');
const app = express();
//3. 设置 session 的中间件
app.use(session({
name: 'sid', //设置cookie的name,默认值是:connect.sid
secret: 'atguigu', //参与加密的字符串(又称签名)
saveUninitialized: false, //是否为每次请求都设置一个cookie用来存储session的id
resave: true, //是否在每次请求时重新保存session
store: MongoStore.create({
mongoUrl: 'mongodb://127.0.0.1:27017/project' //数据库的连接配置
}),
cookie: {
httpOnly: true, // 开启后前端无法通过 JS 操作
maxAge: 1000 * 300 // 这一条 是控制 sessionID 的过期时间的!!!3min后过期
},
}))
//创建 session
app.get('/login', (req, res) => {
//设置session
req.session.username = 'zhangsan';
req.session.email = 'zhangsan@qq.com'
res.send('登录成功');
})
//获取 session
app.get('/home', (req, res) => {
console.log('session的信息');
console.log(req.session.username);
if (req.session.username) {
res.send(`你好 ${req.session.username}`);
}else{
res.send('登录 注册');
}
})
//销毁 session
app.get('/logout', (req, res) => {
//销毁session
// res.send('设置session');
req.session.destroy(() => {
res.send('成功退出');
});
});
app.listen(3000, () => {
console.log('服务已经启动, 端口 ' + 3000 + ' 监听中...');
})
session和cookie的区别
-
存在的位置
- cookie 浏览器
- session 服务器
-
安全性
- cookie是以明文的方式存放在客户端,安全性相对较低
- session存放在服务器端安全性相对较好
-
网络传输量
- cookie设置内容过多会增大报文体积,会影响传输效率
- session存放在服务器,只是通过cookie传递id,不会影响传输效率
-
存储限制
-
浏览器限制单个cookie保存的数据不能超过4k且单个域名下的存储数量也有限制
-
session数据存储在服务器中,没有限制
-
加密算法包md5
单向不可逆加密,通过原数据找到加密数据,不能通过加密数据找到原数据,更好的保护用户的密码
//npm i md5
const md5 = require('md5')
UserModel.create({...req.body,password:md5(req.body.password)},(err,data)=>{
if(err){
res.status(500).send('注册失败,请稍后再试')
return
}
res.render('success',{msg:'注册成功',url: '/login'})
})
token会话控制
- token是服务端生成并且返回给http客户端的一串加密字符串,token中保存着用户信息
- token的作用是实现会话控制可以识别用户的身份主要用于移动端的app
- token的工作流程 填写账号和密码验证身份 验证通过后响应token token一般是响应体返回客户端的
- token的特点
- 服务器的压力更低
- 数据存在客户端
- 相对安全
- 数据加密
- 可以避免csrf(跨站请求的伪造)
- 扩展性更强
- 服务间可以共享
- 增加服务节点更简单
- 服务器的压力更低
// // 导入jwt
const jwt = require('jsonwebtoken')
// 创建token
// let token = jwt.sign(用户数据,加密字符串,配置对象);
let token = jwt.sign({
username:'张三'
},'atguigu',{
expiresIn:60,//单位是秒
})
console.log(token);
let t = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6IuW8oOS4iSIsImlhdCI6MTY5OTc2NDA1NSwiZXhwIjoxNjk5NzY0MTE1fQ.fCeTyBIZPPEMIvuKw2nKq5IHQISo6_l5aPLb9Rp5bXw'
// 校验token
jwt.verify(t,'atguigu',(err,data)=>{
if(err){
console.log('校验失败');
return
}
console.log(data);
})
- 扩展性更强
- 服务间可以共享
- 增加服务节点更简单
// // 导入jwt
const jwt = require('jsonwebtoken')
// 创建token
// let token = jwt.sign(用户数据,加密字符串,配置对象);
let token = jwt.sign({
username:'张三'
},'atguigu',{
expiresIn:60,//单位是秒
})
console.log(token);
let t = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6IuW8oOS4iSIsImlhdCI6MTY5OTc2NDA1NSwiZXhwIjoxNjk5NzY0MTE1fQ.fCeTyBIZPPEMIvuKw2nKq5IHQISo6_l5aPLb9Rp5bXw'
// 校验token
jwt.verify(t,'atguigu',(err,data)=>{
if(err){
console.log('校验失败');
return
}
console.log(data);
})