Node.js -- express 框架

news2024/11/24 2:19:03

文章目录

  • 1. express 使用
  • 2. 路由
    • 2.1 路由的使用
    • 2.2 获取请求报文参数
    • 2.3 获取路由参数
    • 2.4 路由参数练习
  • 3. express 响应设置
  • 4. 中间件
    • 4.1 全局中间件
    • 4.2 路由中间件
    • 4.3 静态资源中间件
  • 5. 获取请求体数据 body-parser
  • 6. 防盗链
  • 7. 路由模块化
  • 8. 模板引擎
    • 8.1 了解EJS
    • 8.2 列表渲染
    • 8.3 条件渲染
    • 8.4 在express 中使用ejs
  • 9. express-generator
  • 10. 文件上传

express是一个基于Node.js平台的极简、灵活的WEB应用开发框架,官方网址:https://www.expressjs.com.cn/
简单来说,express是一个封装好的工具包,封装了很多功能,便于我们开发WEB应用(HTTP服务)

1. express 使用

// 1. 导入express 包
const express = require('express')

// 2. 创建应用对象
const app = express()

// 3. 创建路由
app.get('/home', (req, res) => {
    res.end('Hello Express')
})
// 如果请求方法为GET 且URL中路径为/home 就会执行后面的回调函数

// 4. 监听端口 启动服务器
app.listen(3000, () => {
    console.log('服务已经启动,端口3000 正在监听中...');
})

2. 路由

什么是路由?

官方定义:路由确定了应用程序如何响应客户端对特定端点的请求

2.1 路由的使用

一个路由的组成有请求方法路径回调函数组成
express中提供了一系列方法,可以很方便的使用路由,使用格式如下:

app.< method >(path,callback)

请求报文加载过来之后就开始与路由的规则开始比对;之前的判断我们是通过if / else if 来进行的,而现在express 框架对这种判断方法做了封装

app.get('/', (req, res) => {
    res.end('/')
})

app.post('/login', (req, res)=> {
    res.end('login')
})
app.post()('/login', (req, res) => {
    res.end('login')
})
// 匹配所有的方法
app.all('/test', (req, res) => {
    res.end('test')
})
// 404 响应
app.all('*', (req, res) => {
    res.end('404 not found')
})

2.2 获取请求报文参数

express框架封装了一些API来方便获取请求报文中的数据,并且兼容原生HTTP模块的获取方式

// 原生操作
console.log(req.method);
console.log(req.url);
console.log(req.httpVersion);
console.log(req.headers);
// express操作
console.log(req.path);
console.log(req.query);
// 获取ip
console.log(req.ip);
// 获取请求头
console.log(req.get('host'));

2.3 获取路由参数

路由参数指的是URL路径中的参数(数据)

app.get(‘/:id.html’,(req,res)=>{
res.send(‘商品详情,商品id为’ + req.params.id);
});

const express = require('express')

const app = express()

app.get('/:id.html', (req, res) => {
    // 获取URL 路由参数 其中路径中
    // req.params 存储了请求报文中所有路由id 
    console.log(req.params.id);
    res.setHeader('content-type','text/html;charset=utf-8')
    res.end('test')
})

app.listen(3000, () => {
    console.log('服务已经启动...');
})

2.4 路由参数练习

根据路由参数响应歌手的信息
路径结构如下
/singer/1.html
显示歌手的姓名和图片

const express = require('express')
const {singers} = require('./singers.json')

const app = express()

// 练习内容

app.get('/singer/:id.html', (req, res) => {
    // 获取路由参数
    let { id } = req.params; // 该变量是字符串形式
    // 在数组中寻找对应id的数据
    let result = singers.find(item => {
        if (item.id === Number(id)) {
            return true;
        }
    })
    console.log(result)
    // 判断:如果result 没有数据就 返回404
    if (!result) {
        res.statusCode = 404
        res.end(`<h1>404 not found</h1>`)
    }
    res.end(`
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
    </head>
    <body>
        <h1>${result.singer_name}</h1>
        <img src="${result.singer_pic}" alt="">
    </body>
    </html>
    `);
})
app.listen(3000, () => {
    console.log('服务已经启动...');
})

获取 URL 中的动态参数
通过req.params对象,可以访问到 URL 中,通过:匹配到的动态参数:

3. express 响应设置

express框架封装了一些API来方便给客户端响应数据,并目兼容原生HTTP模块的获取方式

  1. express中设置响应的方式兼容HTTP模块的方式
const express = require('express')
const app = express()
app.get('/response', (req, res) => {
    // 获取请求的路由规则
    app.get("/response", (req, res) => {
        // 1.express中设置响应的方式兼容HTTP模块的方式
        res.statusCode = 404;
        res.statusMessage = 'xxx'
        res.setHeader('abc', 'xyz');
        res.write('响应体')
        res.end('xxx')
    })

在这里插入图片描述
2. express的响应方法


    // 2.express的响应方法
    res.status(500);//设置响应状态码
    res.set('aaa', 'bbb');//设置响应头
    res.send('中文响应不乱码');//设置响应体 自动添加字符集的设置
    // 连贯操作
    res.status(404).set('xxx', 'yyy').send('你好朋友')
   
  1. express的响应方法
 // 3.其他响应
    res.redirect('http://atguigu.com')//重定向 
    res.download('./package.json');//下载响应 返回下载形式的响应
    res.json();//响应JS0N
    res.sendFile(__dirname + '/home.html')//响应文件内容
})

app.listen(3000, () => {
    console.log('服务已启动...');
})

4. 中间件

中间件(Middleware)本质是一个回调函数
中间件函数可以像路由回调一样访问请求对象(request),响应对象(response)

中间件的作用就是使用函数封装公共操作,简化代码

中间件类型:

  • 全局中间件
  • 路由中间件

4.1 全局中间件

每一个请求到达服务端之后都会执行全局中间件函数
(路由函数只有在满足请求方法和请求路径一致时才会执行回调函数)

全局中间件实践:

const express = require('express')
const fs = require('fs')
const path = require('path')
const app = express()
app.get('/home', (req, res) => {
    // 获取url ip
    let { url, ip } = req;
    // 将信息保存在record.log 中
    fs.readFileSync(path.resolve(__dirname + 'record.log'),`${url} ${ip}\r\n`)
    res.end('home')
})
app.all('*', (req, res) => {
    // 获取url ip
    let { url, ip } = req;
    // 将信息保存在record.log 中
    fs.readFileSync(path.resolve(__dirname + 'record.log'),`${url} ${ip}\r\n`)
    res.end('all')
})
app.listen(3000,()=> {
    console.log('服务启动...')
})

如果我们每创建一个路由就在其中定义url和ip 再存入到文件中,那么将会产生很多重复的代码,这时候我们可以让重复的代码部分写入全局中间件中

function recordMiddleware(req,res,next) {
    // 获取url ip
    let { url, ip } = req;
    // 将信息保存在record.log 中
    fs.readFileSync(path.resolve(__dirname + 'record.log'), `${url} ${ip}\r\n`)
    next()// 表示执行完全局中间件函数之后继续执行下面的路由中间件或者其他的全局中间件
}
// 使用全局中间件函数
app.use(recordMiddleware)
app.get('/home', (req, res) => {
    res.end('home')
})
app.all('*', (req, res) => {
    res.end('all')
})

4.2 路由中间件

// 针对/admin/setting的请求,要求URL携带code=521参数,如末携带提示『暗号错误」
// const { log } = require('console')
const express = require('express')
const path = require('path')
const app = express()
let CheckCodeMiddleware = (req, res, next) => {
    // 其中路由中间件函数 必须要加上 表示在满足条件时就可以继续执行next()
    //判断code 参数是否为666
    if (req.query.code === '666') {
        next()
    }
    else {
        res.send('不能调用')
    }
}
app.get('/home', CheckCodeMiddleware, (req, res) => {
    res.send('首页')
});
app.get('/admin', CheckCodeMiddleware, (req, res) => {
    res.send('后台')
});
app.all('*', (req, res) => {
    res.send('all')
});
app.listen(3000, () => {
    console.log('go');
})

4.3 静态资源中间件

静态资源:长时间不发生改变的资源,例如:css,js,图片…

express.static(文件夹路径) --> 返回文件中的全局中间件

app.use(express.static(__dirname+'/public'))

之前我们通过读取文件url ,拼接文件路径,读取文件,响应文件,设置meta 类型等多项操作完成了以上操作,但是在这里一行代码就搞定了!

注意事项:

  1. index.html 为默认打开的资源,也就是可以作为网站首页,因为我们在不添加路径的时候访问网站,返回的会是index.html ,但是这也反映出一个问题(也就是第二个注意事项)!
  2. 如果静态资源与路由规则同时匹配,谁先匹配谁就像响应
  3. 路由响应动态资源,静态资源中间件响应静态资源

练习:
要求:局域网内可以访问小米商城的网页

const express = require('express')
const app = express()
// 静态资源中间件
app.use(express.static(__dirname + '/小米商城'))

app.listen(3000, () => {
    console.log('服务启动');
})

在电脑上win + R 打开命令行,输入ipconfig 查询本机所在局域网,在链接了同一个局域网的手机上可以通过ip:端口号查看同一个网站(比如自己写好的小米商城网页)

5. 获取请求体数据 body-parser

express可以使用body-parser包处理请求体
第一步:安装

npm i body-parser

第二步:导入body-parser包

const bodyParser = require(‘body-parser’);

第三步:获取中间件函数

// 处理querystring格式的请求体
let urlParser = bodyParser.urlencoded({extended:false});
// 处理JSON格式的请求体
let jsonParser = bodyParser.json();

第四步:设置路由中间件,然后使用request.body来获取请求体数据

app.post('/login',urlParser,(request,response)=>{
//获取请求体数据
//console.log(request.body);
//用户名
console.log(request.body.username);
//密码
console.log(request.body.userpass);
response.send('获取请求体数据')
})

6. 防盗链

有些时候我们在网上存了某张图片的网址链接,但是并不能在自己的html 中打开,这是因为这个网站设置了防盗链(禁止该域名之外的其他网站来对该图片网站访问)

防盗链实践:
在设置防盗链之前,访问127.0.0.1:3000 和访问localhost:3000 效果是一样的,可以得到同一个网页;

// 防盗链
const express = require('express')

const app = express()

// 声明中间件
app.use((req, res, next) => {
    // 获取referer
    let referer = req.get('referer')
    if (referer) {
        // 实例化
        let url = new URL(referer)
        let hostname = url.hostname
        if (hostname !== '127.0.0.1') {
            res.status(404).send('<h1>404 Not Found</h1>')
            return
        }
    }
    next()
})

// 静态资源中间件设置
app.use(express.static(__dirname + '/public'))

app.listen(3000, () => {
    console.log('启动!');
})

7. 路由模块化

homeRouter.js:

const express = require('express')
// 创建路由对象
const router = express.Router()

// 创建路由规则
router.get('/settings',  (req, res) => {
    res.send('设置')
});
router.get('/search',  (req, res) => {
    res.send('搜索')
});
router.get('/home', (req, res) => {
    res.send('首页')
});
router.get('/admin', (req, res) => {
    res.send('后台')
});

// 暴露router
module.exports = router

模块化.js:

const express = require('express')

const homeRouter = require('./routes/homeRouter')
const app = express()
// 设置
app.use(homeRouter)

// app.all('*', (req, res) => {
//     res.send('all')
// });
app.listen(3000, () => {
    console.log('go');
})

8. 模板引擎

模板引擎是分离用户界面和业务数据的一种技术
模板引擎也是一种通用技术,多种语言都有。

8.1 了解EJS

EJS是一个高效的Javascript的模板引擎。
官网:https://ejs.co/
中文站:https://ejs.bootcss…com/

EJS 初体验:
简单理解模板引擎就是把html和js 分离开,但这里的js 指的是服务器相关的js 代码。

下面是之前的一个案例,从中我们可以发现html 和js 是混合到了一起的,而ejs 可以将他们分离开。
在这里插入图片描述

const ejs = require('ejs')
const fs = require('fs')

let china = '中国' // 1处
let weather = 'sunny'

// 声明变量
let str = fs.readFileSync('./10-test.html').toString()

// 使用ejs 渲染
let result = ejs.render(str, { china: china, weather })

console.log(result);

render(str,{}) 第二个属性是对象的形式,属性名对应str中的变量名 属性值对应1处的变量名
在这里插入图片描述

8.2 列表渲染

// 列表渲染
const { log } = require('console');
const ejs = require('ejs')
const fs = require('fs')

const xiyouji = ['冒菜','酸甜麻辣烫','凉菜','菠萝']

// 原生js 
// let str = '<ul>'
// xiyouji.forEach(item => {
//     str += `<li>${item}</li>`
// })
// str += '</ul>'

// ejs 渲染
let str = fs.readFileSync('./11-test.html').toString()
let result = ejs.render(str, { xiyouji: xiyouji })

console.log(result);

8.3 条件渲染

通过变量isLogin 决定最终的输出内容
true --> 输出< span>欢迎回来</ span>
false --> 输出< button>登录</button < button >注册</ button>

// 条件渲染
const ejs = require('ejs')
const fs = require('fs')

let isLogin = true
// 原生js
// if (isLogin) {
//     console.log('<span>come back</span>');
// } else {
//     console.log(`<button>登录</button>
//     <button>注册</button>`);
// }

//ejs
let html = fs.readFileSync('./12-test.html').toString()
let result = ejs.render(html, { isLogin: isLogin })
console.log(result);

8.4 在express 中使用ejs

const express = require('express')
const path = require('path')

const app = express()

// 1. 设置模板引擎
app.set('view engine', 'ejs')
// 2. 设置模板文件存放位置 模板文件:具有模板语法内容的文件
app.set('views',path.resolve(__dirname,'./views'))

app.get('/home', (req, res) => {
    // 3. render 响应
    // res.render('模板文件名', '数据')
    let title='在思考中学习!'
    res.render('view', {title})
})

app.listen(3000, () => {
    console.log('go!');
})

9. express-generator

express-generator 是Express 应用程序生成器,帮助我们生成express 文件骨架。

  1. 安装

npm i -g express-generator

  1. express - h/v --> 查看相关帮助
  2. express - e 文件路径 --> 添加ejs 的模板引擎支持
  3. 添加依赖

npm i

10. 文件上传

文件上传场景:
更换头像;网盘上传文件;短视频平台上传视频…

注:
enctype=“multipart/form-data” 是上传表单时表单必要的属性

处理文件上传 – 安装formidable 包

// 显示网页表单
router.get('/portrait', (req, res) => {
  res.render('portrait')
})

// 处理文件上传
router.post('/portrait', (req, res) => {
  // 创建form 对象
  const form = formidable({
    multiples: true,
    // 设置上传文件的保存目录 一般都保存在用户很容易获取到的地方
    uploadDir: __dirname + '/../public/images',
    // 保持文件后缀
    keepExtensions:true

  });

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1639008.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

InfluxDB安装使用介绍

1.介绍 InfluxDB是一个由InfluxData开发的开源时序型数据。它由Go写成&#xff0c;着力于高性能地查询与存储时序型数据。InfluxDB被广泛应用于存储系统的监控数据&#xff0c;IoT行业的实时数据等场景。 2.对常见关系型数据库&#xff08;MySQL&#xff09;的基础概念对比 1…

Spring Cloud——Circuit Breaker上篇

Spring Cloud——Circuit Breaker上篇 一、分布式系统面临的问题1.服务雪崩2.禁止服务雪崩故障 二、Circuit Breaker三、resilience4j——服务熔断和降级1.理论知识2.常用配置3.案例实战&#xff08;1&#xff09;COUNT_BASED&#xff08;计数的滑动窗口&#xff09;&#xff0…

UE4_Niagara_两个模型之间的粒子幻化

学习笔记&#xff0c;仅供参考&#xff01; 操作步骤&#xff1a; 1、新建niagara system&#xff0c;添加空的发射器&#xff0c;渲染改为网格体渲染器&#xff0c;网格体为1M_Cube. 2、创建粒子材质重载。 3、渲染网格体的材质设置&#xff1a; 4、在发射器属性面板&#x…

LeetCode 213 —— 打家劫舍 II

阅读目录 1. 题目2. 解题思路3. 代码实现 1. 题目 2. 解题思路 此题是 LeetCode 198—— 打家劫舍 的升级版&#xff0c;多了一个首尾相连的设定。 因为首尾相连&#xff0c;所以第一个房屋和最后一个房屋只能偷窃其中一个。 所以&#xff0c;第一种方案就是不偷窃最后一个房…

Web APIs 学习归纳6--- BOM浏览器对象

前面几节主要针对DOM进行了学习&#xff0c;现在开始新的内容的学习---DOM浏览器对象。 DOM是更注重页面&#xff08;document&#xff09;内容的设计&#xff0c;但是BOM不仅限于页面&#xff08;document&#xff09;的设计&#xff0c;而是更加全面包括页面的刷新&#xff0…

SpringBoot使用ResponseBodyAdvice和RequestBodyAdvice实现请求体解密、响应体加密

文章目录 一、写在前面二、实现细节1、定义加解密注解2、请求体解密逻辑3、响应体加密逻辑4、测试类5、测试结果 三、源码分析1、RequestResponseBodyMethodProcessor2、RequestBodyAdvice3、ResponseBodyAdvice 一、写在前面 项目中经常需要对接第三方平台&#xff0c;每次对…

redis ZRANGE 使用最详细文档

环境&#xff1a; redis_version:7.2.2 本文参考 redis 官方文档1 语法 ZRANGE key start stop [BYSCORE | BYLEX] [REV] [LIMIT offset count] [WITHSCORES]参数含义key是有序集合的键名start stop在不同语境下&#xff0c;可用值不一样BYSCORE | BYLEX按照分数查询 | 相…

Node.js -- mongoose

文章目录 1. 介绍2. mongoose 连接数据库3. 插入文件4. 字段类型5. 字段值验证6. 文档处理6.1 删除文档6.2 更新文档6.3 读取文档 7. 条件控制8. 个性化读取9. 代码模块化 1. 介绍 Mongoose是一个对象文档模型库&#xff0c;官网http://www.mongoosejs.net/ 方便使用代码操作mo…

2021-10-21 51单片机两位数码管显示0-99循环

缘由单片机两位数码管显示0-99循环-编程语言-CSDN问答 #include "REG52.h" #include<intrins.h> sbit K1 P3^0; sbit K2 P3^1; sbit K3 P3^2; sbit K4 P3^3; sbit bpP3^4; bit k1,wk10,wk20; unsigned char code SmZiFu[]{63,6,91,79,102,109,125,7,127,1…

数据库(MySQL) —— DDL语句

MySQL—— DDL语句 什么是MySQL的DDL语句查看所有的所有数据库查看当前使用的数据库库操作创建库使用数据库删除库 表操作创建表查询当前库中所有的表查询表结构查询指定表的建表语句删除表 表修改删除字段修改数据类型修改字段名和字段类型重命名表删除指定表并重新创建该表 我…

c3 笔记7 css基本语法

相关内容&#xff1a;字体、段落、词间距、文字效果&#xff08;对齐、上下标、阴影&#xff09;、背景图、背景渐变、…… 单位pt与px的差别pt是印刷使用的字号单位&#xff0c;不管屏幕分辨率是多少&#xff0c;打印到纸上看起来都是相同的&#xff0c;lot的长度是0.01384英寸…

Mybatis四种实例化对象方式

代码准备 创建mybatis-config.xml <?xml version"1.0" encoding"UTF-8" ?> <!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration…

【golang学习之旅】深入理解字符串string数据类型

系列文章 【golang学习之旅】报错&#xff1a;a declared but not used 【golang学习之旅】Go 的基本数据类型 目录 系列文章使用示例string的底层数据结构关于字符串复制字符串是不可变的如何高效的进行字符串拼接&#xff1f; 使用示例 Go 语言中的字符串只是一个只读的字节…

CUDA CPP Unity Compute Shader

为学 开始一个新的学习计划&#xff0c;涵盖&#xff1a; 主题学习内容CUDAProfessional CUDA C Programming/NVIDIA CUDA初级教程视频(周斌)CCPrimer / The Cherno CPPUnity Compute ShaderUdemy Learn to Write Unity Compute ShadersLinear AlgebraMIT 18.06 Prof.Gilbert…

typescript类型检查和原始类型

typescript类型检查和原始类型 类型检查 非严格类型是typescript默认的类型检查模式&#xff0c;在该模式下&#xff0c;类型检查的规则相对轻松&#xff0c;不会对undefined和null值做过多的限制&#xff0c;允许将undefined和null值赋给string类型的变量。进行JavaScript代…

【算法】高精度乘法

前言 最近在参加某个比赛的时候遇到了这个问题&#xff0c;用字符串表示时&#xff0c;长度能达到15&#xff0c;所以针对大数乘法写一篇文章。 高精度 * 低精度 在这种场景下&#xff0c;一般都是给定一个无法用int或long long 存储的数&#xff0c;再给定一个能用int或lon…

第74天:漏洞发现-Web框架中间件插件BurpSuite浏览器被动主动探针

目录 思维导图 前置知识 案例一&#xff1a;浏览器插件-辅助&资产&漏洞库-Hack-Tools&Fofa_view&Pentestkit 案例二&#xff1a; BurpSuite 插件-被动&特定扫描-Fiora&Fastjson&Shiro&Log4j 思维导图 前置知识 目标&#xff1a; 1. 用…

Linux 进程间通信之命名管道

&#x1f493;博主CSDN主页:麻辣韭菜&#x1f493;   ⏩专栏分类&#xff1a;Linux知识分享⏪   &#x1f69a;代码仓库:Linux代码练习&#x1f69a;   &#x1f339;关注我&#x1faf5;带你学习更多Linux知识   &#x1f51d; 目录 前言 命名管道 创建一个命名管道 …

八大排序详解:动图、代码、注释

目录 何为八大排序&#xff1f; 直接插入排序 排序过程解读 直接插入排序的特性总结&#xff1a; 希尔排序 希尔排序的特性总结&#xff1a; 直接选择排序 直接选择排序的特性总结&#xff1a; 堆排序 直接选择排序的特性总结&#xff1a; 冒泡排序 快速排序 1.Hoa…

全景剖析阿里云容器网络数据链路(七):Terway DataPath V2(Terway≥1.8.0)

作者&#xff1a;余凯 前言 近几年&#xff0c;企业基础设施云原生化的趋势越来越强烈&#xff0c;从最开始的IaaS化到现在的微服务化&#xff0c;客户的颗粒度精细化和可观测性的需求更加强烈。容器网络为了满足客户更高性能和更高的密度&#xff0c;也一直在高速的发展和演…