文章目录

  • 前言
  • 1 Express
  • 1.1 什么是express
  • 1.2 为什么需要express
  • 1.3 手动安装手动配置
  • 2 Express基本使用
  • 2.1 主要代码及注释
  • 3 处理网页
  • 3.1 处理静态资源
  • 3.2 什么是ejs(模板引擎)
  • 3.2.1 ejs的特点
  • 3.2.2 ejs的成员函数
  • 3.3.3 ejs的常用标签
  • 3.3 处理动态资源
  • 在模板中使用数据
  • 4 处理路由
  • 4.1 应用级别中路由
  • 4.2 处理路由第二种方式
  • 5 会话技术
  • 5.1 什么是会话?
  • 5.2 会话技术
  • 5.3 cookie作用
  • 5.4 cookie记录上一次访问的时间
  • 5.5 session的使用
  • 6 Express中间件
  • 6.1 next介绍
  • 6.2 next使用
  • 6.3 next正确使用方式
  • 6.4 express中间件
  • 7 Express脚手架
  • 7.1 通过express搭建项目
  • 7.2 生成的app.js


前言

这部分主要是node使用express框架之后的简写版本。

1 Express

express:表达;快速(这里取快速的翻译)

1.1 什么是express

Express是一个基于NodeJS的Web Server开发框架, 能够帮助我们快速的搭建Web服务器。

1.2 为什么需要express

  1. 利用原生的NodeJS开发Web服务器,
    我们需要处理很多繁琐且没有技术含量的内容。
    例如: 获取路由->解析路由->分配路由->处理路由等。
    但是有了Express之后, 就能帮助我们省去大量繁琐的环节, 让我们只用关注核心业务逻辑。
  2. 利用原生的NodeJS开发Web服务器,
    我们需要自己手动去实现静态/动态资源处理, get/post参数的解析, cookie的解析, 日志处理等。
    但是有了Express之后, 已经有现成的插件帮我们实现了上述功能。
  3. 所以作为单身的程序猿(媛), 如果你还想留一些时间去约会, 那么Express是你的最佳选择。

1.3 手动安装手动配置

  传送门   安装:npm i express -S

2 Express基本使用

2.1 主要代码及注释

// 导入express
const express = require("express");
// express执行(调用express方法),创建服务端实例对象
const app  = express();
// req,res 并不是原生node中的req,res
// 它是在原生node的基本上进行增强
// 虽然此处req,res进行了增强,但是也可以使用原生node中的api
app.get("/",(req,res)=>{//路由  默认是/  一个地址,对应了一个响应
    // res.writeHead(200,{'Content-type':'text/plain;charset=utf-8'})//解决字符乱码问题
    // res.end("www.badu.com")//响应数据
    //之前的原生方法也能使用
    res.send("hello express")

})

app.get("/login",(req,res)=>{ // 一个地址,对应了一个响应
    res.send("<h1>登录页面</h1>")
})
//监听端口
app.listen(3000,()=>{//告诉服务端需要监听哪一个端口
    console.log("server is running on 3000");
})

res.send([body|status], [body]) 既可以直接发送内容,也可以第一个参数状态,第二个参数内容。
如果直接发送内容的话,状态会被自动补全;
详细介绍:传送门

我们向服务器发一个请求,核心有两种请求方式:
1)get请求 偏向于向服务器要数据 当然也可以把数据给服务器
A)浏览器的地址栏就可以发起get请求
B)a标签的href也可以发起get请求
C)link标签的href也可以发起get请求
D)script 标签的 src也可以发起get请求
E)img标签的src也可以发起get请求
F)form表示也可以发起Get表示

特点:
1)会数据放到地址栏中 不太安全
2)post请求 偏向于把数据扔给服务器

利用form表示发起get请求:
1)action表示此请求地址
2)method请求的方式
3)表单中的input必须要有一个name属性

<form action="http://localhost:3333/doreg" method="get">
    <ul>
        <li>用户名:<input type="text" name="username"></li>
        <li>密码:<input type="password" name="pwd"></li>
        <li><input type="submit" value="注册"></li>
    </ul>
</form>

3 处理网页

3.1 处理静态资源

const express = require("express");
const path = require("path")
const app  = express();
//可以配置多个静态资源目录
app.use(express.static('public'))
// app.use(express.static('files'))
// app.use('/static', express.static('files'))
========================express托管静态资源
// use 表示使用中间件 express内部自带一个中间件 express.static()
// express.static 此中间件就可以托管静态资源 是一个内置的中间件
// console.log(path.join(__dirname,"public"));
app.use(express.static(path.join(__dirname, 'public')));

项目位置:

node express 时区 express nodejs_node express 时区

3.2 什么是ejs(模板引擎)

  ejs:一个模板引擎,默认情况下,你的模板中写的数据都是假数据,一般数据都是来自于数据库的。如果把数据库中的数据取出来,放到需要替换数据的地方,此时就是一个真数据,这个流程叫服务端渲染

3.2.1 ejs的特点
- 快速编译和渲染
    - 简单的模板标签
    - 自定义标记分隔符
    - 支持文本包含
    - 支持浏览器端和服务器端
    - 模板静态缓存
    - 支持express视图系统
3.2.2 ejs的成员函数
Render(str,data,[option]):直接渲染字符串并生成html
     str:需要解析的字符串模板
     data:数据
     option:配置选项
3.3.3 ejs的常用标签
<% %>流程控制标签
     <%= %>输出标签(原文输出HTML标签)
     <%- %>输出标签(HTML会被浏览器解析)
     <%# %>注释标签
     % 对标记进行转义

3.3 处理动态资源

  模板:就是前端程序员写好的html页面,html页面中的数据默认都是假数据,我们需要把它里面的假数据替换成真实的数据,此时就需要使用模板。一般情况下,是把模板放在views下面的,如下:

node express 时区 express nodejs_javascript_02

原本是.html需要换为.ejs,也可以用别的方法代替。

在模板中使用数据

var ejs = require("ejs");// 导入ejs模块
==================================路径写法一
app.use(express.static(path.join(__dirname,"public")))
// 1)告诉express,你的模板在什么地方
app.set("views",path.join(__dirname,"views"));//绝对路径的写法
==================================路径写法二
// 把./views目录设置为模板文件根,html文件模板放在view目录中
app.set("views", "./views");//告诉express,模板放在views下面
==============================================================================
// 设置模板引擎为ejs
// 2)告诉express,你使用的模板引擎是什么 ejs 除了ejs模板引擎之外,还有其它的模板引擎
app.set('view engine', 'ejs')
app.get("/xxx",(req,res)=>{
// res.send("hello express")
// 把数据渲染到模板中 通过res.render就可以渲染模板,同时就可以给模板上绑定数据
res.render('xxx',{msg:"dadaima"});
})
<h1>我是一个模板</h1>
<h2><%= msg %></h2>

4 处理路由

4.1 应用级别中路由

const express = require("express");
// app叫应用
const app = express();
app.get("/reg", (req, res) => {
    res.send("<h1>注册页面</h1>")
})
app.get("/login", (req, res) => {
    res.send("<h1>登录页面</h1>")
})
app.get("/cart", (req, res) => {
    res.send("<h1>购物车页面</h1>")
})
app.post('/api/user/register', (req, res, next) => {
    res.json({
        name: 'xq',
        age: 18,
        method: 'post'
    });
});

app.listen(3000, () => {
    console.log("server is running on 3000");
})

注意:

1.响应对象的json方法是express给响应对象扩展的
    2.这个方法会自动将对象转换成字符串之后返回
    3.这个方法还会自动帮助我们设置响应头

4.2 处理路由第二种方式

在项目的根目录下,创建一个routes文件夹:

node express 时区 express nodejs_后端_03

  不同的模块,有不同的路由文件,这里的routes和controller的意思是一样的。user.jsgoods.js里面的路由,叫二级路由

user.js代码如下:

const express = require("express");
// router叫路由对象
const router = express.Router();
// 说白了,就是我们前面讲的controller
// 二级路由
router.get("/login", (req, res, next) => {
    res.send("<h1>登录页面</h1>")
})
router.get("/reg", (req, res, next) => {
    res.send("<h1>注册页面</h1>")
})
// 导出路由对象
module.exports = router;

goodes.js类似user.js
在入口文件引入独立的模块

// app.js
const express = require("express");
// 引入二级路由文件
const userRouter = require("./routes/user")
const goodsRouter = require("./routes/goods")
const app = express();
// 一级路由 当访问/api/user时,就把这个路由交给userRouter来处理
app.use("/api/user", userRouter)
app.use("/api/goods", goodsRouter)
app.listen(3000, () => {
    console.log("server is running on 3000");
})

5 会话技术

Cookie:浏览器端的会话技术。
Session:服务器端的会话技术。

5.1 什么是会话?

  日常生活中:从拨通电话到挂断电话之间的一连串你问我答的过程就是一个会话。
  B/S架构中:从浏览器第一次给服务器发送请求时,建立会话;直到有一方断开,会话结束。
一次会话:包含多次请求响应。

5.2 会话技术

  问题:Http是一个无状态协议,同一个会话的连续两个请求相互独立,彼此并不了解。

  会话技术能弥补http协议无状态带来的麻烦。

作用:用于存储浏览器与服务器在请求和响应过程中产生的数据

  在一次会话中(多次请求响应), 共享数据

客户端会话技术:cookie 服务器端会话技术:session

node express 时区 express nodejs_数据_04

5.3 cookie作用

Cookie作用:在一次会话的多次请求之间共享数据,将数据保存到客户端(浏览器)

服务器可以给客户端种植一个cookie:
    cookie: 小甜点 饼干 cookie本质就是存储数据的
    服务器给客户端种植了一个cookie,那么这个cookie就存储在客户端。
    一旦种植了,后面每一次请求,都会带上这个cookie。
    
服务器给客户端种植了一个cookie,cookie保存在什么地方?
答:在开发者工具中,找到application,在左侧找到cookie选项,服务器种植的cookie就存在在这个地方。

ookie的特点:

  1. cookie保存在客户端(浏览器), 往往是由服务器产生发送给浏览器
  2. cookie只能保存字符串, 格式是entry(name : value)
  3. cookie的大小有限制: 4k
  4. 一般, 同一域名下的cookie限制数量50个

使用:(需要模块:npm i cookie-parser

const express = require("express")
const path = require("path")
const cookieParser = require('cookie-parser')
let app = express();
app.use(express.static(path.join(__dirname,'public')))
// 配置cookie
app.use(cookieParser())
app.get("/",(req,res)=>{
    // 需要在服务端种植一个cookie,种到了浏览器的时面
    // 后面,每一次请求,浏览器都会带上这个cookie

    // 给客户端种植一个cookie
    // res.cookie("usrename","wangcai");  // 默认情况下,会话结束,cookie就死了

    // 活7天  设置cookie的生存时间
    // res.cookie("username","wc",{maxAge:60000*60*24*7})

    // 获取浏览器带过来的cookie
    console.log("获取cookie:",req.cookies);
    res.send("hello 客户端~")
})

app.listen(3000,()=>{
    console.log("server is running 3000~");
})

node express 时区 express nodejs_数据_05


总结:

默认cookie的生存时间:
     种植:res.cookie("username","wangcai");
     当浏览器关闭后,cookie就没了,这个过程,叫一次会话。默认情况下,会话结束了,cookie就没有了。
     
第一次,会种植一个cookie,后面再次去请求服务器时,它会把cookie携带上。
使用cookie的缺点:
     1)除了第1次请求服务器,后面每一次请求服务器,都要带上cookie,浪费带宽,请求速度会慢一点。
     2)因为cookie是存在浏览器端的,我们可以销毁掉,可以篡改它
     3)有的用户,会在浏览器端,禁用cookie
     ....
设置cookie的生存周期:
res.cookie("username","wc",{maxAge:60000*60*24*7,httpOnly:true})
除了第1次请求,后面每一次请求,都会带上cookie,在服务器端,就可以

获取cookie,需要模块:npm i cookie-parser 使用:

let cookieParser = require("cookie-parser")
app.use(cookieParser())
req.cookies // 得到客户端请求时,传递过一过来cookie

5.4 cookie记录上一次访问的时间

app.get("/", (req, res) => {
    // 获取cookie 第1次获取不到,值是und
    let last = req.cookies.last;
    // 第1次访问服务器 需要种植一个cookie
    //在浏览器种植时间一年。
    res.cookie("last", new Date().toLocaleString(), { maxAge: 60000 * 60 * 24 * 356 });
    if (last) {
        res.send(`你上一次访问的时间是:${last}`)
    } else {
        // 第1次访问
        res.send(`这是你第1次访问本网站`)
    }
})

5.5 session的使用

session的作用:在一次会话的多次请求之间共享数据,将数据保存到服务器端。
Session基于Cookie技术实现
session是服务器端的会话技术

从浏览器第一次向服务器发起请求建立会话, 直到其中一方断开为止会话结束。
session的特点:

  1. session存储数据在服务器
  2. session存储任意类型的数据(Object)
  3. session存储大小和数量没有限制(在服务器内存)
  4. session存储相对安全

node express 时区 express nodejs_javascript_06

const session = require('express-session')
// 配置session
app.use(session({
    secret: 'keyboard cat',
    resave: false,
    saveUninitialized: true,
    // session是基于cookie的
    cookie: { maxAge:60000*10 }//id存在10分钟
}))
app.get("/",(req,res)=>{

    // session也是存数数据的,你可以把session理解成一片存储数据的区域
    // 你不需要种植cookie,内部会自动帮你种植
    req.session.last = "2021-09-08"; // 当请求/时,给session区域保存一个数据

    // 后面的请求,班长会带着编号来请求,会根据编号找到他对应的session
    console.log("获取班长的session中对应的数据:",req.session.last);

    res.send("hello session")

})

cookie和session的选择

  1. cookie将数据保存在浏览器端,数据相对不安全.
    建议敏感的或大量的数据不要放在cookie中,而且数据大小是有限制的
    成本低,对服务器要求不高
  2. session将数据保存在服务器端内存,数据相对安全.
    数据的大小要比cookie中数据灵活很多
    成本较高,对服务器压力较大

6 Express中间件

  路由是一个特殊的中间件,如果你要定义一个正经的中间件,必须要加next。next表示放行。

6.1 next介绍

express-next方法:
     1.use既可以处理没有路由地址的请求, 也可以处理有路由地址请求
     2.use既可以处理get请求, 也可以处理post请求
     3.在处理请求的时候是从上至下的判断的, 哪一个先满足就哪一个来处理
     4.如果在处理请求的回调函数中没有调用next方法, 那么处理完之后就不会继续往下判断了
     5.如果在处理请求的回调函数中调用了next方法,那么处理完之后还会继续往下判断

6.2 next使用

// 中间件的书写顺序需要特别注意
// 如果没有写路径,表示所有的请求都要经过此中间件
app.use((req,res,next)=>{
    console.log("所有请求都要经过~");
    // 放行
    next()
})

// 不分是post还是get
// 普通的中间件
app.use("/abc",(req,res,next)=>{
    console.log("我是一个中间件 111 ");
    // 放行
    next()
})

app.use("/abc",(req,res,next)=>{//一样的名字会继续执行  直到没有next或者路径不一样
    console.log("我是一个中间件 222");
    // 放行  才能走到下面的路由 注释掉不行
    next()
})

/// 路由
app.get('/abc',(req, res, next)=>{
    console.log('get1 /api');
    next();
});

6.3 next正确使用方式

1)通过next方法, 我们可以将同一个请求的多个业务逻辑拆分到不同的方法中处理。
2)这样可以提升代码的可读性和可维护性, 以及保证代码的单一性。

6.4 express中间件

1.什么是中间件?
- 中间件的本质就是一个函数, 这个函数接收3个参数request请求对象、response响应对象、next函数
- 当请求进来,会从第一个中间件开始进行匹配。如果匹配则进入,如果不匹配,则向后依次对比匹配
2.中间件的作用?
- 将一个请求的处理过程,分发到多个环节中,目的效率高,便于维护。即每个环节专门干一件事
3.中间件的分类
     3.1 应用级别中间件
     绑定到app实例上的中间件
     例如: app.get / app.post
     3.2 路由级别中间件
     绑定到router实例上的中间件
     例如: router.get / router.post
     3.3 错误处理中间件
     与其他中间件函数的定义基本相同,
     不同之处在于错误处理函数多了一个变量:err,即它有4个变量:err, req, res, next
     3.4 内置中间件
     express.static()、express.json()、express.urlencoded()、...
     3.5 第三方中间件
     cookie-parser、...

7 Express脚手架

7.1 通过express搭建项目

安装脚手架:
    npm install express-generator -g
    
通过脚手架去创建项目:
    express myapp
进入myapp中:
    cd myapp
    
跑环境:
    npm i
运行项目:
    npm start (是npm run start的简写)
    
默认创建出来的项目,它使用的模板引擎是jade模板引擎。
后面创建项目时,生的项目使用的模板引擎是ejs的,创建项目是指定模板引擎,如下:
命令:express -e myapp2
如果在已经创建好的文件夹中使用:express -e ./

7.2 生成的app.js

var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');

// http-errors 用来处理错误的
var createError = require('http-errors');
// 打印日志
var logger = require('morgan');

// 引入二级路由模块(路由文件)
var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');

// 创建app应用
var app = express();

// 告诉epxress,模板放在了什么地方
app.set('views', path.join(__dirname, 'views'));
// 告诉express,使用的模板引擎是jade
app.set('view engine', 'jade');

// 使用中间件
app.use(logger('dev')); // 日志中间件
// 解析前端传的json数据
app.use(express.json());
// 解析前端传的表单数据
app.use(express.urlencoded({ extended: false }));
// 解析cookie
app.use(cookieParser());
// 托管静态资源
app.use(express.static(path.join(__dirname, 'public')));

// 配置一级路由
app.use('/', indexRouter);
app.use('/users', usersRouter);


// 配置中间件
app.use(function(req, res, next) {
  // 放行
  next(createError(404));
});

// 配置中间件   err
// 叫错误处理中间件
app.use(function(err, req, res, next) {
  // set locals, only providing error in development
  res.locals.message = err.message;
  res.locals.error = req.app.get('env') === 'development' ? err : {};

  // render the error page
  res.status(err.status || 500);
  res.render('error');
});

module.exports = app;