express 基础知识实战

1 Express框架介绍与安装

1.1 Express 安装

生成配置文件package.json

npm init --yes

安装 Express 框架,就是使用 npm 的命令。

npm install express --save
yarn add express --save

初次使用

const express = require('express')
//实例化express
const app = express()
const port = 3000 //端口

//配置路由
app.get('/', (req, res) => {
  res.send('Hello World!')
})

//监听端口
app.listen(port, () => {
  console.log(`Example app listening at http://localhost:${port}`)
})

2 Express中的路由

路由(Routing)是由一个 URI(或者叫路径)和一个特定的 HTTP 方法(GET、POST 等)组成的,涉及到应用如何响应客户端对某个网站节点的访问
Express中的路由配置非常简单

const express = require('express')
const app=express()

app.get("/",(req,res)=>{
  res.send("路由配置完成")
})

app.listen(3000)

配置post路由

app.post("/doLogin",(req,res)=>{   //post:增加数据
  console.log("执行登录")
  res.send("执行登录")
})

配置put路由

app.put("/editUser",(req,res)=>{  //put:主要用于修改数据
  console.log("修改用户")
  res.send("修改用户")
})

配置delete路由

app.delete("/editUser",(req,res)=>{  //put:主要用于修改数据
  console.log("修改用户")
  res.send("修改用户")
})

动态路由的配置路由的时候要注意顺序
动态路由在下面

app.get("/article/add",(req,res)=>{
  res.send("article add")
})

app.get("/article/:id",(req,res)=>{
  var id=req.params["id"]    //获取动态路由
  res.send("动态路由"+id)
})

路由get中的参数

//get 传值  http://localhost:3000/product?id=123&cid=123
app.get("/product",(req,res)=>{
  let query = req.query   //获取get传值
  console.log(query)
  res.send("product-"+query.id)
})

3 express 工程化

Express:是比较轻量级的框架,不自带许多工程化目录,需要自己配置
如下配置:新建routes目录

将模块分开为三大模块,并在入口文件引入
在这里插入图片描述

//引入外部模块
const admin = require("./routes/admin")
const api = require("./routes/api")
const index = require("./routes/index")

//挂载外部模块
app.use("/admin", admin)
app.use("/app", api)
app.use("/", index)

举例:当admin模块中还有很多模块就再次抽离
在这里插入图片描述
admin.js挂载子模块

const express = require("express")
const router = express.Router()

//引入模块
const user = require("./admin/user")
const nav = require("./admin/nav")

router.get("/", (req, res) => {
  res.send("后台管理中心")
})
//挂载模块
router.use("/user", user)
router.use("/nav", nav)

module.exports = router

子模块则延续父模块路由,如:/admin/user

const express = require("express")

const router = express.Router()

router.get("/", (req, res) => {
  res.send("用户列表")
})
router.get("/add", (req, res) => {
  res.send("增加用户")
})
router.get("/edit", (req, res) => {
  res.send("修改用户")
})
router.get("/del", (req, res) => {
  res.send("删除用户")
})


module.exports = router

3.1 Express生成器(express-generator)

https://www.expressjs.com.cn/starter/generator.html
通过应用生成器工具 express-generator 可以快速创建一个应用的骨架。
安装成功后
可使用express 查看相关用法

express -h

  Usage: express [options] [dir]

  Options:

    -h, --help          输出使用方法
        --version       输出版本号
    -e, --ejs           添加对 ejs 模板引擎的支持
        --hbs           添加对 handlebars 模板引擎的支持
        --pug           添加对 pug 模板引擎的支持
    -H, --hogan         添加对 hogan.js 模板引擎的支持
        --no-view       创建不带视图引擎的项目
    -v, --view <engine> 添加对视图引擎(view) <engine> 的支持 (ejs|hbs|hjs|jade|pug|twig|vash) (默认是 jade 模板引擎)
    -c, --css <engine>  添加样式表引擎 <engine> 的支持 (less|stylus|compass|sass) (默认是普通的 css 文件)
        --git           添加 .gitignore
    -f, --force         强制在非空目录下创建

生成项目

#view = 模板引擎
express--view = ejs 项目名

yarn install
npm install

4 Express使用Ejs模板引擎

4.1 安装

npm install ejs --save
yarn add ejs --save

4.2 Ejs的使用

const express = require("express")
//引入ejs
const ejs = require("ejs");
const app = express()

app.get("/", (req, res) => {
  //render渲染模板
  res.render("index.ejs", {
    //传入数据
  })
})

app.listen(3000)
4.2.1 ejs传输数据
app.get("/", (req, res) => {
  //对象假数据
  let userinfo = {
    username: "Ting",
    age: "20"
  }
  // 标签假数据
  let article = "<h3>我是标价数据</h3>"
  res.render("index.ejs", {
    //传入数据
    userinfo: userinfo,
    article: article
  })
})
4.2.2 模板渲染数据
<h2>我是一个ejs模板</h2>
//%= 解析普通文本 %-可解析html
<p>我叫<%=userinfo.username%>年龄<%=userinfo.age%></p>
<p><%-article%></p>

4.3 条件判断语句

<%if(flag==true){%>
	<strong>flag=true</strong>
<%}%>



<%if(score>=60){%>
	<p>及格</p>
<%}else{%>
	不及格
<%}%>

4.4 循环语句

<ul>
    <%for(let i=0;i<list.length;i++){%>
        <li><%=list[i]%></li>
    <%}%>        
</ul>
<br>

<ul>
    <%for(let i=0;i<newsList.length;i++){%>
        <li><%=newsList[i].title%></li>
    <%}%>        
</ul>

引入公共文件入引入foot.ejs

<%-include('foot.html')%>

4.5 配置模板引擎后缀

//配置模板引擎后缀为:html
app.engine("html",ejs.__express);

//view目录下的ejs
app.set("view engine","ejs");

4.6 静态文件

app.use(express.static("static"))

5 封装Express路由

尝试模拟封装类似express的路由
express配置路由方式如下

app.get("/", function (req, res) {
    res.send('hello world')
})

那么需要一个app函数来调用

let app=function(req,res){
    // console.log('调用app方法')
    if(G['/login']){
        G['/login'](req,res);  //执行方法
    }
}

当不同请求时调用不同路径方法,需要注册不同方法

let G={};//保存注册的路由
//静态方法
app.get=function(str,cb){   
    //注册方法
    G[str]=cb;
}

那么初版完成了注册和配置调用

5.1 封装route

将上面代码封装到route文件里,并暴露app方法

const url= require("url");

let G={};

let app=function(req,res){
    // console.log('调用app方法')
    let pathname=url.parse(req.url).pathname;
    if(G[pathname]){
        G[pathname](req,res);  //执行方法
    }else{
        res.writeHead(404, { 'Content-Type': 'text/html;charset="utf-8"' });
        res.end('页面不存在');
    }
}
app.get=function(str,cb){   
    //注册方法
    G[str]=cb;  

}
module.exports=app;

5.2 引入http模块

引入route模块和http模块并配置路由

const http = require("http");
const app=require('./module/route')

//注册web服务
http.createServer(app).listen(3000);

//配置路由
app.get('/',function(req,res){
    res.writeHead(200, { 'Content-Type': 'text/html;charset="utf-8"' });
    res.end('首页');
})

5.3 加入post

当我们post的时候可能会和get请求路径一样
那么我们定义G时可以分开定义不同方法

const url = require("url");

let server = () => {
    let G = {};
    //把get 和 post分开
    G._get={};
    G._post={};
    let app = function (req, res) {
        //扩展res的方法
        changeRes(res);
        let pathname = url.parse(req.url).pathname;
        //获取请求类型
        let method=req.method.toLowerCase();
        if (G['_'+method][pathname]) {
            if(method=="get"){ 
                G['_'+method][pathname](req, res);  //执行方法
            }else if(method=="post"){
                //post  获取post的数据 把它绑定到req.body
                let postData = '';
                req.on('data', (chunk) => {
                    postData += chunk;
                })
                req.on('end', () => {                  
                   req.body = postData;
                   G['_'+method][pathname](req, res);  //执行方法
                })
            }
        } else {
            res.writeHead(404, { 'Content-Type': 'text/html;charset="utf-8"' });
            res.end('页面不存在');
        }
    }
    app.get = function (str, cb) {
        //注册方法
        G._get[str] = cb;     
    }
    app.post = function (str, cb) {
        //注册方法
        G._post[str] = cb;      
    }
    return app;
}
module.exports = server();

5.4 添加静态页配置

配置静态web服务目录

const fs = require('fs');
const path = require('path');
const url = require('url');

//根据后缀名获取文件类型
function getFileMime(extname) {
    var data = fs.readFileSync('./data/mime.json'); //同步方法
    let mimeObj = JSON.parse(data.toString());
    return mimeObj[extname];
}
//静态web服务的方法
function initStatic(req, res, staticPath) {
    //1、获取地址
    let pathname = url.parse(req.url).pathname;
    let extname = path.extname(pathname);
  
    //2、通过fs模块读取文件
    if (extname) {//如果有后缀名用静态web服务处理
        try {
            let data = fs.readFileSync('./' + staticPath + pathname);
            if (data) {
                let mime = getFileMime(extname);
                res.writeHead(200, { 'Content-Type': '' + mime + ';charset="utf-8"' });
                res.end(data);
            }
        } catch (error) {
            console.log(error);
        }
    }
}

let server = () => {
    let G = {
        _get: {},
        _post: {},
        staticPath: 'static' //,默认静态web目录
    };
    let app = function (req, res) {
        //扩展res的方法
        changeRes(res);
        //配置静态web服务
        initStatic(req, res, G.staticPath);

        let pathname = url.parse(req.url).pathname;
        //获取请求类型
        let method = req.method.toLowerCase();
        let extname = path.extname(pathname);
        if (!extname) {  //如果有后缀名用静态web处理
            if (G['_' + method][pathname]) {
                if (method == "get") {
                    G['_' + method][pathname](req, res);  //执行方法
                } else {
                    //post  获取post的数据 把它绑定到req.body
                    let postData = '';
                    req.on('data', (chunk) => {
                        postData += chunk;
                    })
                    req.on('end', () => {
                        req.body = postData;
                        G['_' + method][pathname](req, res);  //执行方法
                    })
                }
            } else {
                res.writeHead(404, { 'Content-Type': 'text/html;charset="utf-8"' });
                res.end('页面不存在');
            }
        }
    }
    //get请求
    app.get = function (str, cb) {
        //注册方法
        G._get[str] = cb;
    }
    //post请求
    app.post = function (str, cb) {
        //注册方法
        G._post[str] = cb;
    }
    //配置静态web服务目录
    app.static = function (staticPath) {
        G.staticPath = staticPath;
    }
    return app;
}
module.exports = server();

调用配置

app.static("public")

6 Express中间件

Express的中间件,用来实现各种功能,对于同一个网络请求,可能同时有多个匹配的中间件,一般顺序执行。而 next() 则是把执行控制权,从上一个中间件,转移到下一个中间件的函数。

6.1 应用级中间件

express通过app.use来配置应用级中间件
调用next方法,匹配下一个中间件

//应用级中间件
app.use((req, res, next) => {
  console.log("添加中间件")
  //需要匹配下面中间件就要添加next回调
  next()
})

6.2 路由级中间件

路由级中间件用的比较少
一般情况下,路由匹配到一个就不会向下匹配了

app.get("/article/add",(req,res)=>{
  res.send("article add")
})

app.get("/article/:id",(req,res)=>{
  var id=req.params["id"]    //获取动态路由
  res.send("动态路由"+id)
})

加入next()回调就会向下匹配

app.get("/article/add",(req,res,next)=>{
  res.send("article add")
  next()
})

app.get("/article/:id",(req,res)=>{
  var id=req.params["id"]    //获取动态路由
  res.send("动态路由"+id)
})

6.3 错误处理中间件

和应用级中间件使用差不多,用于错误处理

app.use((req, res, next) => {
  res.status(404).send("404")
})

6.4 内置中间件

如:静态文件目录匹配中间件

app.use(express.static("static"))

6.5 第三方中间件

第三方中间件各种各样,学express就是需要学习各种中间件
如:配置body-parse中间件获取post提交数据

  1. 安装第三方中间件
npm install body-parser --save
yarn add body-parser --save
  1. 配置中间件
app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json())
  1. 使用body
app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json())

7 Express使用Cookie和Session

7.1 Cookie 的使用

Express 中要使用 Cookie 的话,我们需要使用 cookie-parser 模块来实现

7.1.1 安装
npm instlal cookie-parser --save
yarn add cookie-parser --save
7.1.2 引入并配置
const cookieParser = require('cookie-parser');
//配置中间件
app.use(cookieParser());

//设置cookie(key, value, {过期时间})
res.cookie("name",'zhangsan',{maxAge: 900000, httpOnly: true});

//获取cookie
req.cookie.name
7.1.3 设置参数
//设置cookie(key, value, {过期时间})
res.cookie("name",'zhangsan',{maxAge: 900000, httpOnly: true});
参数解释
domain域名 name=value:键值对,可以设置要保存的 Key/Value,注意这里的 name不能和其他属性项的名字一样
Expires过期时间(秒),在设置的某个时间点后该 Cookie 就会失效,如expires=Wednesday, 09-Nov-99 23:12:40 GMT
maxAge最大失效时间(毫秒),设置在多少后失效
secure当 secure 值为 true 时,cookie 在 HTTP 中是无效,在 HTTPS 中才有效
Path表示 cookie 影响到的路路径,如 path=/。如果路径不能匹配时,浏览器则不发送这个 Cookie
httpOnly是微软对 COOKIE 做的扩展。如果在 COOKIE 中设置了“httpOnly”属性,则通过程序(JS 脚本、applet 等)将无法读取到 COOKIE 信息,防止 XSS 攻击产生
singed表示是否签名 cookie, 设为 true 会对这个 cookie 签名,这样就需要用res.signedCookies 而不是 res.cookies 访问它。被篡改的签名 cookie 会被服务器拒绝,并且 cookie 值会重置为它的原始值

设置cookie 的几种方法

res.cookie('rememberme', '1', { maxAge: 900000, httpOnly: true })
res.cookie('name', 'tobi', { domain: '.example.com', path: '/admin', secure: true });
res.cookie('rememberme', '1', { expires: new Date(Date.now() + 900000), httpOnly: true });

删除cookie

//重置为空
res.cookie('rememberme', '', { expires: new Date(0)});
res.cookie('username','zhangsan',{domain:'.ccc.com',maxAge:0,httpOnly:true});
7.1.4 加密Cookie

配置中间件的时候需要传参

var cookieParser = require('cookie-parser'); 
app.use(cookieParser('123456'));

设置cookie 的时候配置signed 属性

res.cookie('userinfo','hahaha',{
  domain:'.ccc.com',
  maxAge:900000,
  httpOnly:true,
  signed:true //加密
});

signedCookies 调用设置的cookie

console.log(req.signedCookies);

7.2 Session的使用

当浏览器访问服务器并发送第一次请求时,服务器端会创建一个 session对象,生成一个类似于 key,value的键值对, 然后将 key(cookie)返回到浏览器(客户)端,浏览器下次再访问时,携带 key(cookie),找到对应的 session(value)。

7.2.1 安装

安装 express-session

npm install express-session --save
yarn add express-session --save

配置中间件

app.use(session({
  secret: 'keyboard cat', //生成dession签名(随意写)
  resave: true,						//强制保存session
  saveUninitialized: true //强制将为初始化的session存储
  cookie: {
		maxAge: 1000*60,
  	secure: false //true表示只有https才能访问cookie
	}
}))

7.2.2 设置参数

参数解释
secret一个 String 类型的字符串,作为服务器端生成 session 的签名。
name返回客户端的 key 的名称,默认为connect.sid,也可以自己设置。
resave强制保存 session 即使它并没有变化,。默认为 false。 don’t save session if unmodified
saveUninitialized强制将未初始化的 session 存储。当新建了一个 session 且未设定属性或值时,它就处于未初始化状态。在设定一个 cookie 前,这对于登陆验证,减轻服务端存储压力,权限控制是有帮助的。(默认:true)。建议手动添加。
cookie设置返回到前端 key 的属性,默认值为{ path: ‘/’, httpOnly: true, secure: false,maxAge: null }。
rolling在每次请求时强行设置 cookie,这将重置 cookie 过期时间(默认:false)

7.2.3 常用方法

//设置 session
req.session.username='张三'; 

//销毁 session
req.session.destroy(function(err) {})

//获取session
req.session.username

//重新设置 cookie 的过期时间
req.session.cookie.maxAge=0;

7.2.4 Session 保存到数据库

保存到mongodb数据库,保存到其他数据库操作类似
https://www.npmjs.com/package/connect-redis
https://www.npmjs.com/package/connect-mysql

安装connect-mongo 模块

npm i connect-mongo --save
yarn add connect-mongo --save

引入

const MongoStore = require('connect-mongo')(session);

配置中间件

app.use(session({
    secret: 'this is session', //服务器端生成 session 的签名
    name:"itying", //修改session对应cookie的名称
    resave: false, //强制保存 session 即使它并没有变化
    saveUninitialized: true, //强制将未初始化的 session 存储
    cookie: { 
        maxAge:1000*60*30,
        secure: false  // true 表示只有https协议才能访问cookie  
    },
    rolling:true,  //在每次请求时强行设置 cookie,这将重置 cookie 过期时间(默认:false)
    //配置保存数据库
    store: new MongoStore({
        url: 'mongodb://127.0.0.1:27017/shop',      
        touchAfter: 24 * 3600 // 不管发出了多少请求 在24小时内只更新一次session, 除非你改变了这个session 
    })
}))

8 Express结合multer上传文件

Multer 是一个 node.js 中间件,用于处理 multipart/form-data 类型的表单数据,它主要用于上传文件。它是写在 busboy 之上非常高效。
注意: Multer 不会处理任何非 multipart/form-data 类型的表单数据。

8.1安装

npm install --save multer

借助multer模块上传文件

var multer = require('multer') 
//配置
var storage = multer.diskStorage({
	//文件保存路径 注意路径必须存在
  destination: function (req, file, cb) { 
  	cb(null, 'public/upload/')
	},
  //修改文件名称
  filename: function (req, file, cb) {
  	//获取后缀名
  	let fileFormat = (file.originalname).split(".");
    //拼接后缀名
		cb(null,Date.now() + "." + fileFormat[fileFormat.length - 1]);
   }
})

const upload = multer({ storage: storage })

8.2 封装上传模块

新建model目录->tools.js文件封装

const multer = require('multer');
const path = require('path');
const sd = require('silly-datetime');
const mkdirp = require('mkdirp')
let tools={
    multer(){
        var storage = multer.diskStorage({
            //配置上传的目录
            destination: async (req, file, cb) => {
                //1、获取当前日期 20200703
                let day=sd.format(new Date(), 'YYYYMMDD');
                // static/upload/20200703
                let dir=path.join("static/upload",day)
                //2、按照日期生成图片存储目录  mkdirp是一个异步方法
                await mkdirp(dir)   
                //上传之前目录必须存在
                cb(null, dir) 
            },
            //修改上传后的文件名
            filename: (req, file, cb)=> {
                //1、获取后缀名
                let extname= path.extname(file.originalname);
                //2、根据时间戳生成文件名
                cb(null, Date.now()+extname)
            }
        })
        
        var upload = multer({ storage: storage })
        return upload;
    },
    md5(){
    }
}

module.exports=tools
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值