express框架
express框架
以下为学习过程中的极简提炼笔记,以供重温巩固学习
学习准备
准备工作
学习目的
express框架
- 背景:
- 如:在JavaScript中,安装node.js环境,引入HTTP模块使用,以搭建http服务,给客户端浏览器返回服务端的响应结果
- 用此模块实现服务端功能时,代码不方便效率不高,因此在实际开发中,很少直接采用此方法(现代开发都是组件化,引入工具、框架等现成模块)
认识express框架
介绍
- express 是一个基于 Node.js 平台的极简、灵活的 WEB 应用开发框架,官方网址:https://www.expressjs.com.cn/
- 简单来说,express 是一个封装好的工具包,封装了很多功能,便于我们开发 WEB 应用(HTTP 服务)
- Express 是一个保持最小规模的灵活的 Node.js Web 应用程序开发框架,为 Web 和移动应用程序提供一组强大的功能。
- 使用您所选择的各种 HTTP 实用工具和中间件,快速方便地创建强大的 API
- Express 提供精简的基本 Web 应用程序功能,而不会隐藏您了解和青睐的 Node.js 功能
- Express 是一个轻量、灵活的框架,其核心功能极少, 可通过 Express 中间件 模块对其进行扩展。
下载与安装 express
- express 本身是一个 npm 包,所以可以通过 npm 安装
npm init
npm i express
- 按照如下步骤操作,体验express使用:
- 创建 JS 文件,键入如下代码
//1. 导入 express,引入包 const express = require('express'); //2. 创建应用对象 const app = express(); //3. 创建路由规则 app.get('/home', (req, res) => { // req 是请求报文的封装对象 // res 是响应报文的封装对象 // 浏览器发送的请求为get,且符合第一个参数,路径为'/home'时,触发回调,执行响应报文res.end返回 res.end('hello express server'); }); //4. 监听端口 启动服务 app.listen(3000, () => { console.log('服务已经启动, 端口监听为 3000...'); });
- 命令行下执行该脚本
node <文件名>
# 或者
nodemon <文件名>
- 然后在浏览器就可以访问
http://127.0.0.1:3000/ # 与路径对不上,返回的是404 http://127.0.0.1:3000/home 👌
express 路由 定义及使用
什么是路由
- 官方定义:
路由确定了应用程序如何响应客户端对特定端点的请求
- 逻辑:根据请求的路径,决定执行哪个对应的回调函数
- 官方定义:
路由的使用
- 一个路由的组成有
请求方法
,路径
和回调函数
组成
- 一个路由的组成有
express 中提供了一系列方法,可以很方便的使用路由,使用格式如下:
// 使用对象.方法名(参数1路径,参数2回调函数)
app.<method>(path,callback)
代码示例
//导入 express
const express = require('express');
//创建应用对象
const app = express();
//创建路由
app.get('/home', (req, res) => {
res.end('hello express');
});
//首页路由
app.get('/', (req, res) => {
console.log(req.ip);
res.end('home');
});
//post
app.post('/login', (req, res) => {
res.end('login login')
});
//匹配所有的方法
app.all('/test', (req, res) => {
res.end('test test');
})
//404 响应
app.all('*', (req, res) => {
res.end('404 not Found')
});
//监听端口, 启动服务
app.listen(3000, () => {
console.log('服务已经启动, 端口 3000 正在监听中....')
})
- 可以使用express封装的send,可以自动将数据转换成合适的格式,比如自动添加字符集设置,发往客户端
//导入 express
const express = require('express');
//创建应用对象
const app = express();
//创建 get 路由
app.get('/home', (req, res) => {
res.send('网站首页');
});
//首页路由
app.get('/', (req, res) => {
res.send('我才是真正的首页');
});
//创建 post 路由
app.post('/login', (req, res) => {
res.send('登录成功');
});
//匹配所有的请求方法
app.all('/search', (req, res) => {
res.send('1 秒钟为您找到相关结果约 100,000,000 个');
});
//自定义 404 路由
app.all("*", (req, res) => {
res.send('<h1>404 Not Found</h1>')
});
//监听端口 启动服务
app.listen(3000, () => {
console.log('服务已经启动, 端口监听为 3000');
});
获取请求参数
- express 框架封装了一些 API 来方便获取请求报文中的数据,并且兼容原生 HTTP 模块的获取方式
//导入 express
const express = require('express');
//创建应用对象
const app = express();
//获取请求的路由规则
app.get('/request', (req, res) => {
//1. 获取报文的方式与原生 HTTP 获取方式是兼容的
// 原生HTTP操作
console.log(req.method);
console.log(req.url);
console.log(req.httpVersion);
console.log(req.headers);
//2. express 独有的获取报文的方式
// express 封装的、独有的获取报文操作
// 获取路径
console.log(req.path);
// 获取查询字符串
console.log(req.query); // 『相对重要』
// 获取 客户端ip地址
console.log(req.ip);
// 获取指定的请求头
console.log(req.get('host'));
res.send('请求报文的获取');
});
//启动服务
app.listen(3000, () => {
console.log('服务已经启动, 端口 3000 正在监听中....')
});
获取路由参数
- 路由参数指的是
URL 路径中的参数(数据)
app.get('/:id.html', (req, res) => {
res.send('商品详情, 商品 id 为' + req.params.id);
});
//导入 express
const express = require('express');
//创建应用对象
const app = express();
//创建路由
app.get('/:id.html', (req, res) => {
// 通过'/:id.html'传参id占位符,param是req请求对象的属性,存储了所有的路由参数
// req.params.id获取 URL 路由参数,与占位符字母一致
console.log(req.params.id);
res.setHeader('content-type', 'text/html;charset=utf-8');
res.end('商品详情');
});
//监听端口, 启动服务
app.listen(3000, () => {
console.log('服务已经启动, 端口 3000 正在监听中....')
})
//导入 express
const express = require('express');
//导入 json 文件
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;
}
});
//判断
if (!result) {
res.statusCode = 404;
res.end(`<h1>404 Not Found</h1>`)
return;
}
res.end(`
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h2>${result.singer_name}</h2>
<img src='${result.singer_pic}' />
</body>
</html>`);
});
//监听端口, 启动服务
app.listen(3000, () => {
console.log('服务已经启动, 端口 3000 正在监听中....')
})
express 一般响应&其他响应
- express 框架封装了一些 API 来方便给客户端响应数据,并且兼容原生 HTTP 模块的获取方式
//获取请求的路由规则
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 的响应方法
res.status(500); //设置响应状态码
res.set('xxx', 'yyy');//设置响应头
res.send('中文响应不乱码');//设置响应体
// 方法支持连贯操作
res.status(404).set('xxx', 'yyy').send('你好朋友')
//3. 其他响应
res.redirect('http://atguigu.com')//重定向
res.download('./package.json');//下载响应
res.json();//响应 JSON
res.sendFile(__dirname + '/home.html') //响应文件内容
});
//导入 express
const express = require('express');
//创建应用对象
const app = express();
//创建路由
app.get('/response', (req, res) => {
//原生响应
// res.statusCode = 404;
// res.statusMessage = 'love';
// res.setHeader('xxx', 'yyy');
// res.write('hello express ')
// res.end('response');
//express 响应
// res.status(500);
// res.set('aaa','bbb');
// res.send('你好 Express');
res.status(500).set('abc', 'def').send('这都是 OK 的');
});
//监听端口, 启动服务
app.listen(3000, () => {
console.log('服务已经启动, 端口 3000 正在监听中....')
})
//导入 express
const express = require('express');
//创建应用对象
const app = express();
//创建路由
app.get('/other', (req, res) => {
//跳转响应(重定向)
res.redirect('http://atguigu.com');
//下载响应(传入文件的绝对路径,响应时是下载形式的响应,响应报文提示attachment)
res.download(__dirname + '/package.json');
// JSON 响应(接口响应)
res.json({
name: '尚硅谷',
slogon: '让天下没有难学的技术'
})
//响应文件内容
res.sendFile(__dirname + '/test.html');// path.resolve()
});
//监听端口, 启动服务
app.listen(3000, () => {
console.log('服务已经启动, 端口 3000 正在监听中....')
})
express 中间件
中间件的定义、作用,及类型
定义:
中间件(Middleware)本质是一个回调函数
中间件函数
可以像路由回调一样访问请求对象(request)
和响应对象(response)
中间件函数
既可以获取请求报文的内容,同时可以对响应结果作设置
作用:
中间件的作用
就是使用函数封装公共操作,简化代码
类型:
- 全局中间件
- 接收每个请求,处理请求,再转给后续的路由回调执行
- 可以简单理解:车站进站口
- 实际应用场景:例如服务器的访问日志
- 路由中间件
- 满足某个路由规则,执行对应的回调函数/中间件
- 只对一部分请求作约束
- 可以简单理解:车站检票口
- 实际应用场景:校验用户身份,校验用户权限,放到需要授权的路由规则中,实现权限管理
- 全局中间件
设计定义、应用全局中间件
每一个请求
到达服务端之后 都会执行全局中间件函数
注:安装 Template String Converter 插件,当遇到${}输入时,自动将'单引号',变为模板字符串``反引号`
声明中间件函数
let recordMiddleware = function (request, response, next) {
//实现功能代码
//......
//执行next函数(当如果希望执行完中间件函数之后,仍然继续执行路由中的回调函数,必须调用next)
next();
}
- 应用中间件
app.use(recordMiddleware);
声明时可以直接将匿名函数传递给 use
app.use(function (request, response, next) {
//实现功能代码
//.....
//执行next函数(当如果希望执行完中间件函数之后,仍然继续执行路由中的回调函数,必须调用next)
next();
});
- 多个全局中间件
- express 允许使用 app.use() 定义多个全局中间件
app.use(function (request, response, next) {
console.log('定义第一个中间件');
next();
});
app.use(function (request, response, next) {
console.log('定义第二个中间件');
next();
});
/**
* 记录每个请求的 url 与 IP 地址
*/
//导入 express
const express = require('express');
const fs = require('fs');
const path = require('path');
//创建应用对象
const app = express();
// 前置公共代码,声明中间件函数及使用函数
//声明中间件函数
function recordMiddleware(req, res, next){
//获取 url 和 ip
let {url, ip} = req;
//将信息保存在文件中 access.log
fs.appendFileSync(path.resolve(__dirname, './access.log'), `${url} ${ip}\r\n`);
//调用 next,调用后续的回调函数
next();
}
//使用中间件函数,应用对象.use(函数)
app.use(recordMiddleware);
//创建路由
app.get('/home', (req, res) => {
res.send('前台首页');
});
app.get('/admin', (req, res) => {
res.send('后台首页');
});
app.all('*',(req, res) => {
res.send('<h1>404 Not Found</h1>')
})
//监听端口, 启动服务
app.listen(3000, () => {
console.log('服务已经启动, 端口 3000 正在监听中....')
})
定义路由中间件
- 如果
只需要对某一些路由进行功能封装
,则就需要路由中间件,声明中间件&封装提取出来 - 用法:使用中间件函数,放到受约束的路由规则中,放在路径后面
- 执行逻辑:接收到过来的请求,满足路径后,先执行中间件的代码,满足中间件然后再跑next,执行回调函数路由回调;如果不满足中间件,就在中间件拦截提前res返回了
- 实际应用场景:校验用户身份,校验用户权限,放到需要授权的路由规则中,实现权限管理
调用格式如下:
app.get('/路径', `中间件函数`, (request, response) => {
});
app.get('/路径', `中间件函数1`, `中间件函数2`, (request, response) => {
});
/**
* 针对 /admin /setting 的请求, 要求 URL 携带 code=521 参数, 如未携带提示『暗号错误』
* 经过报文传过来的内容,都转化为了 字符串
*/
//导入 express
const express = require('express');
//创建应用对象
const app = express();
//创建路由
app.get('/home', (req, res) => {
res.send('前台首页');
});
//声明中间件,封装
let checkCodeMiddleware = (req, res, next) => {
//判断 URL 中是否 code 参数等于 521
if(req.query.code === '521'){
// 满足条件的情况下,继续跑后续的路由回调
next();
}else{
res.send('暗号错误');
}
}
//后台,使用中间件函数,放到受约束的路由规则中,放在路径后,满足路径后,先执行中间件的代码1,然后再跑回调函数
app.get('/admin', checkCodeMiddleware, (req, res) => {
res.send('后台首页');
});
//后台设置
app.get('/setting', checkCodeMiddleware, (req, res) => {
res.send('设置页面');
});
app.all('*',(req, res) => {
res.send('<h1>404 Not Found</h1>')
})
//监听端口, 启动服务
app.listen(3000, () => {
console.log('服务已经启动, 端口 3000 正在监听中....')
})
静态资源中间件
- express 框架内置处理静态资源的中间件
- express.static()为中间件函数,调用时接收一个 文件夹路径参数,此文件夹路径参数即为静态资源文件夹目录
- 除了响应文件内容外,该中间件还自动设置了文件资源的Content-Type响应资源的 MINE 类型,还设置了字符集
//引入express框架
const express = require('express');
//创建服务对象
const app = express();
//静态资源中间件的设置,将当前文件夹下的public目录作为网站的根目录
app.use(express.static('./public')); //当然这个目录中都是一些静态资源
//如果访问的内容经常变化,还是需要设置路由
//但是,在这里有一个问题,如果public目录下有index.html文件,单独也有index.html的路由,
//则谁书写在前,优先执行谁
app.get('/index.html', (request, response) => {
respsonse.send('首页');
});
//监听端口
app.listen(3000, () => {
console.log('3000 端口启动....');
});
//导入 express
const express = require('express');
//创建应用对象
const app = express();
//创建路由 可调整排序,在前就先执行
app.get('/', (req, res) => {
res.send('我才是首页~~~');
});
//静态资源中间件,设置静态资源文件夹目录 可调整排序,在前就先执行
app.use(express.static(__dirname + '/public'));
//监听端口, 启动服务
app.listen(3000, () => {
console.log('服务已经启动, 端口 3000 正在监听中....')
})
注意事项:
- index.html 文件为默认打开的资源
- 浏览器发送请求时,路径不写内容,默认路径就是
/
,也就是根路径,服务端将根路径请求,设index.html为默认打开的资源
- 如果静态资源与路由规则同时匹配,谁先匹配谁就响应
- 按照代码执行顺序,谁在前先执行/匹配上,就执行谁
- 路由响应动态资源,静态资源中间件响应静态资源
- 路由响应动态资源:如搜索结果、动态排行信息等
- 静态资源:css、图片、视频等
//导入 express
const express = require('express');
//创建应用对象
const app = express();
//设置静态资源中间件,设置静态资源文件夹目录
app.use(express.static(__dirname + '/尚品汇'));
//监听端口, 启动服务
app.listen(3000, () => {
console.log('服务已经启动, 端口 3000 正在监听中....')
})
获取请求体数据 body-parser
- express 可以使用 body-parser 包处理请求体
- body-parser 包,本质也是一个中间件,方便我们在express框架中提取请求体内容
- 选择解析相应格式请求体的中间件,获取中间件函数
- 路由规则中,在路径后配中间件函数,用于提取请求体数据
- 中间件函数执行完毕后,会往请求对象req上,增加一个body属性
第一步:安装包
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('获取请求体数据');
});
获取到的请求体数据格式:
[Object: null prototype] { username: 'admin', userpass: '123456' }
/**
* 按照要求搭建 HTTP 服务
*
* GET /login 显示表单网页
* POST /login 获取表单中的『用户名』和『密码』
*/
//导入 express
const express = require('express');
const bodyParser = require('body-parser')
//创建应用对象
const app = express();
//获取中间件函数,解析 JSON 格式的请求体的中间件
// const jsonParser = bodyParser.json()
//获取中间件函数,解析 querystring 格式请求体的中间件
const urlencodedParser = bodyParser.urlencoded({ extended: false })
//创建路由规则
app.get('/login', (req, res) => {
// res.send('表单页面')
//响应 HTML 文件内容
res.sendFile(__dirname + '/11_form.html');
});
//post 规则,通过bodyParser的中间件函数,提取请求体数据
app.post('/login', urlencodedParser, (req, res) => {
//获取 用户名 和 密码
console.log(req.body);
res.send('获取用户的数据')
});
//启动服务
app.listen(3000, () => {
console.log('server is running...');
})
中间件应用:图片防盗链
- 防盗链:防止外部网站盗用网站资源(禁止该域名之外的其他网站对资源作访问)
- referer请求头:自动携带当前网页的协议域名和端口,向服务器发送请求;服务端通过此请求头参数,判断请求来源
//导入 express
const express = require('express');
//创建应用对象
const app = express();
//声明中间件
app.use((req, res, next) => {
//检测请求头中的 referer 是否为 127.0.0.1
//获取 referer
let referer = req.get('referer');
if(referer){
//实例化
let url = new URL(referer);
//获取 hostname
let hostname = url.hostname;
//判断
if(hostname !== '127.0.0.1'){
//响应 404
res.status(404).send('<h1>404 Not Found</h1>');
return;
}
}
next();
});
//静态资源中间件设置
app.use(express.static(__dirname + '/public'));
//监听端口, 启动服务
app.listen(3000, () => {
console.log('服务已经启动, 端口 3000 正在监听中....')
})
Router路由模块化
express中Router的定义、作用,及使用
定义:
- express 中的 Router 是一个完整的中间件和路由系统对象,可以看做是一个小型的 app 对象
作用:
- 对路由功能拆分,进行模块化,更好的管理路由
使用:
- 创建独立的 JS 文件 homeRouter.js 前台路由,如下
//1. 导入 express
const express = require('express');
//2. 创建路由对象
const router = express.Router();
//3. 创建路由规则,在 router 对象身上添加路由
//创建路由
router.get('/home', (req, res) => {
res.send('前台首页');
});
//创建路由
router.get('/search', (req, res) => {
res.send('内容搜索');
});
//4. 暴露 router
module.exports = router;
- 创建独立的 JS 文件 adminRouter.js 后台路由,如下
//1. 导入 express
const express = require('express');
//2. 创建路由对象
const router = express.Router();
// router.use()
// 3. 创建路由规则,在 router 对象身上添加路由
//后台
router.get('/admin', (req, res) => {
res.send('后台首页');
});
//后台设置
router.get('/setting', (req, res) => {
res.send('设置页面');
});
//4. 暴露 router
module.exports = router;
- 主文件中引入两个子路由文件,设置和使用
/**
* 针对 /admin /setting 的请求, 要求 URL 携带 code=521 参数, 如未携带提示『暗号错误』
*/
//导入 express
const express = require('express');
//5.引入子路由文件
const homeRouter = require('./routes/homeRouter');
const adminRouter = require('./routes/adminRouter');
//创建应用对象
const app = express();
//6.设置和使用中间件
app.use(homeRouter);
app.use(adminRouter);
app.all('*',(req, res) => {
res.send('<h1>404 Not Found</h1>')
})
//监听端口, 启动服务
app.listen(3000, () => {
console.log('服务已经启动, 端口 3000 正在监听中....')
})
EJS 模板引擎
EJS、模板引擎的定义
模板引擎的定义
- 模板引擎是分离
用户界面和业务数据
的一种技术 - 是通识性知识,在很多语言中都有,如Java,python,PHP
- 随着前后端分离,后端使用这种技术的情况减少
- 模板引擎是分离
EJS 是一个高效的 Javascript 的模板引擎
- 分离
用户界面和业务数据
,可以理解为,分离HTML和(服务端的)JavaScript - 官网: https://ejs.co/
- 中文站:https://ejs.bootcss.com/
- 分离
EJS模板引擎,即框架语言下,模板语法的原理,如vue中的template
体验使用 EJS
下载安装EJS
npm i ejs --save
# npm i 也是支持自动向上寻找的
//1.引入ejs
const ejs = require('ejs');
//2.定义数据
let person = ['张三', '李四', '王二麻子'];
//3.ejs解析模板返回结构
//<%= %> 是ejs解析内容的标记,作用是输出当前表达式的执行结构
let html = ejs.render('<%= person.join(",") %>', { person: person });
//4.输出结果
console.log(html);
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h2>我爱你 <%= china %></h2>
<p><%= weather %></p>
</body>
</html>
//1. 安装 EJS
//2. 导入 EJS
const ejs = require('ejs');
const fs = require('fs');
//字符串
let china = '中国';
// let str = `我爱你 ${china}`;
// let str = `我爱你 <%= china %>`;
let weather = '今天天气不错~';
//声明变量
let str = fs.readFileSync('./01_html.html').toString();
//使用 ejs 渲染
let result = ejs.render(str, {china: china, weather});
console.log(result);
EJS 常用语法
执行JS代码
<% code %>
输出转义的数据到模板上
<%= code %>
输出非转义的数据到模板上
<%- code %>
- ejs.render
<% %>
是 EJS 内部语法,用来输出某个表达式的值- 第二个参数,传入数据,是一个对象{}
- ejs会将
<% %>
中的内容,替换成第二个参数对象中的内容 - 变量有等号
<%= 变量 %>
,js代码/语句无等号<% %>
EJS 列表渲染
const ejs = require('ejs');
//西游记
const xiyou = ['唐僧','孙悟空','猪八戒','沙僧'];
//原生 JS
// let str = '<ul>';
// xiyou.forEach(item => {
// str += `<li>${item}</li>`;
// })
// //闭合 ul
// str += '</ul>';
// console.log(str);
// EJS 实现
const fs = require('fs');
let html = fs.readFileSync('./02_西游.html').toString();
let result = ejs.render(html, {xiyou:xiyou});
console.log(result);
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>西游四人组</title>
</head>
<body>
<h2>西游四人组</h2>
<ul>
<% xiyou.forEach(item => { %>
<li><%= item %></li>
<% }) %>
</ul>
</body>
</html>
EJS 条件渲染
/**
* 通过 isLogin 决定最终的输出内容
* true 输出『<span>欢迎回来</span>』
* false 输出『<button>登录</button> <button>注册</button>』
*/
// 导入 ejs
const ejs = require('ejs');
const fs = require('fs');
//变量
let isLogin = true;
//原生 JS
// if(isLogin){
// console.log('<span>欢迎回来</span>')
// }else{
// console.log('<button>登录</button> <button>注册</button>');
// }
//EJS 实现
//读取 HTML 内容
let html = fs.readFileSync('./03_home.html').toString();
let result = ejs.render(html, {isLogin: isLogin});
console.log(result);
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<header>
<% if(isLogin){ %>
<span>欢迎回来</span>
<% }else{ %>
<button>登录</button> <button>注册</button>
<% } %>
</header>
</body>
</html>
Express 中使用 EJS
- 目的:通过框架返回给前端数据时,实现后端的html与js分离,方便模板化引用和修改
- 模板文件: 具有模板语法内容的文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h2><%= title %></h2>
</body>
</html>
//导入 express
const express = require('express');
//导入 path
const path = require('path');
//创建应用对象
const app = express();
//1. 设置模板引擎,设置express使用的模板引擎为ejs
app.set('view engine', 'ejs');// 还有其他模板引擎,如:pug twing
//2. 设置模板文件存放位置 模板文件: 具有模板语法内容的文件
app.set('views', path.resolve(__dirname, './views'));
//创建路由
app.get('/home', (req, res) => {
//3. render 响应
// res.render('模板的文件名', '数据');
//声明变量
let title = '尚硅谷 - 让天下没有难学的技术';
res.render('home', {title});
//4. 创建模板文件
});
//监听端口, 启动服务
app.listen(3000, () => {
console.log('服务已经启动, 端口 3000 正在监听中....')
})
express-generator 应用程序生成器
express-generator应用程序生成器是express官方提供的工具
- 通过应用生成器工具 express-generator 可以快速创建一个应用的骨架(搭建文件结构和基础代码)。
- 本质就是脚手架的原理
安装
npx express-generator
# 或 全局安装
npm install -g express-generator
# -h 参数可以列出所有可用的命令行参数
express -h
# 创建骨架,添加ejs模板引擎支持
express -e 安装目录文件夹名称
var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', indexRouter);// 设置路由前缀
app.use('/users', usersRouter);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
next(createError(404));
});
// app.all('*')
// error handler
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;
Express框架实战案例
文件上传报文查看
- 场景:上传文件、上传更换头像等等
- 文件上传也是在发送http请求报文
var express = require('express');
var router = express.Router();
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index', { title: 'Express' });
});
//显示网页的 (表单)
router.get('/portrait', (req, res) => {
res.render('portrait');
});
//处理文件上传
router.post('/portrait', (req, res) => {
res.send('成功');
});
module.exports = router;
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>文件上传</title>
</head>
<body>
<h2>文件上传</h2>
<hr>
<!-- 文件上传的必需的属性 -->
<form action="/portrait" method="post" enctype="multipart/form-data">
用户名: <input type="text" name="username"><br>
头像: <input type="file" name="portrait"><br>
<hr>
<button>点击提交</button>
</form>
</body>
</html>
npm start
Express框架处理文件上传
通过 formidable 这个包实现
两个对象
- fields这个对象只存一般字段:文本框text 单选框radio 多选框checkbox select
- file文件上传字段
流程:
- 图片从客户端发服务端
- 服务端保存在静态资源文件夹下
- 将访问的url,转到数据库存储,并返回用户端url
var express = require('express');
var router = express.Router();
//导入formidable包
const formidable = require('formidable');
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index', { title: 'Express' });
});
//显示网页的 (表单)
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
});
//解析请求报文
form.parse(req, (err, fields, files) => {
if (err) {
next(err);
return;
}
// 两个对象
// console.log(fields);// fields这个对象只存一般字段,text radio checkbox select
// console.log(files); // file
//服务器保存该图片的访问 URL
// /images/8ad3d5e36012212ba7642c000.jpg
let url = '/images/' + files.portrait.newFilename;// 将来将此数据保存在数据库中
res.send(url);
});
});
module.exports = router;
案例实践记账本-搭建基本结构
- 先通过框架,快速搭建基本结构,记账本项目目录文件夹为:accounts
# 框架搭建
express -e accounts
# 装依赖
npm i
# package.json改为nodemon,随编辑重启服务
"start": "nodemon ./bin/www"
# 启动项目
npm start
- 鼠标悬停在引入包/文件的路径,按住ctrl,再点击,就可以跳转打开引入目录/文件
var express =require('express');
var router =express.Router();
//记账本的列表
router.get('/account',function(req, res, next){
res.send('账本列表');
});
//添加记录
router.get('/account/create',function(req, res, next){
res.send('添加记录');
});
module.exports =router;
案例实践记账本-响应静态页面
- 记账本的账单列表
- 先将index.html静态结构,放入模板文件accounts\views\list.ejs
- 在模板文件中放入静态页面结构
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<link
href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.css"
rel="stylesheet"
/>
<style>
label {
font-weight: normal;
}
.panel-body .glyphicon-remove{
display: none;
}
.panel-body:hover .glyphicon-remove{
display: inline-block
}
</style>
</head>
<body>
<div class="container">
<div class="row">
<div class="col-xs-12 col-lg-8 col-lg-offset-2">
<h2>记账本</h2>
<hr />
<div class="accounts">
<div class="panel panel-danger">
<div class="panel-heading">2023-04-05</div>
<div class="panel-body">
<div class="col-xs-6">抽烟只抽煊赫门,一生只爱一个人</div>
<div class="col-xs-2 text-center">
<span class="label label-warning">支出</span>
</div>
<div class="col-xs-2 text-right">25 元</div>
<div class="col-xs-2 text-right">
<span
class="glyphicon glyphicon-remove"
aria-hidden="true"
></span>
</div>
</div>
</div>
<div class="panel panel-success">
<div class="panel-heading">2023-04-15</div>
<div class="panel-body">
<div class="col-xs-6">3 月份发工资</div>
<div class="col-xs-2 text-center">
<span class="label label-success">收入</span>
</div>
<div class="col-xs-2 text-right">4396 元</div>
<div class="col-xs-2 text-right">
<span
class="glyphicon glyphicon-remove"
aria-hidden="true"
></span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</body>
</html>
- 添加记录页
- 先将create.html静态结构,放入模板文件accounts\views\create.ejs
- 启动服务,观察,发现样式丢失,此时样式是通过相对路径引入
- 将css、js样式文件夹,放入静态资源目录accounts\public下,然后将模板文件accounts\views\create.ejs中的样式引入,改为绝对路径
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>添加记录</title>
<!-- 改为绝对路径引入 -->
<link
href="/css/bootstrap.css"
rel="stylesheet"
/>
<link href="/css/bootstrap-datepicker.css" rel="stylesheet">
</head>
<body>
<div class="container">
<div class="row">
<div class="col-xs-12 col-lg-8 col-lg-offset-2">
<h2>添加记录</h2>
<hr />
<form>
<div class="form-group">
<label for="item">事项</label>
<input
type="text"
class="form-control"
id="item"
/>
</div>
<div class="form-group">
<label for="time">发生时间</label>
<input
type="text"
class="form-control"
id="time"
/>
</div>
<div class="form-group">
<label for="type">类型</label>
<select class="form-control" id="type">
<option value="">支出</option>
<option value="">收入</option>
</select>
</div>
<div class="form-group">
<label for="account">金额</label>
<input
type="text"
class="form-control"
id="account"
/>
</div>
<div class="form-group">
<label for="remarks">备注</label>
<textarea class="form-control" id="remarks"></textarea>
</div>
<hr>
<button type="submit" class="btn btn-primary btn-block">添加</button>
</form>
</div>
</div>
</div>
<!-- 改为绝对路径引入 -->
<script src="/js/jquery.min.js"></script>
<script src="/js/bootstrap.min.js"></script>
<script src="/js/bootstrap-datepicker.min.js"></script>
<script src="/js/bootstrap-datepicker.zh-CN.min.js"></script>
<script src="/js/main.js"></script>
</body>
</html>
var express =require('express');
var router =express.Router();
//记账本的列表
router.get('/account',function(req, res, next){
res.render('list');
});
//添加记录
router.get('/account/create',function(req, res, next){
res.render('create');
});
module.exports =router;
案例实践记账本-获取表单数据
- 表单数据传给服务端,每一个表单项,需要设置有name值,添加name属性
- 表单标签设置
<form method="post" action="/account">
- 路由规则新增路由记录
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>添加记录</title>
<link
href="/css/bootstrap.css"
rel="stylesheet"
/>
<link href="/css/bootstrap-datepicker.css" rel="stylesheet">
</head>
<body>
<div class="container">
<div class="row">
<div class="col-xs-12 col-lg-8 col-lg-offset-2">
<h2>添加记录</h2>
<hr />
<form method="post" action="/account">
<div class="form-group">
<label for="item">事项</label>
<input
name="title"
type="text"
class="form-control"
id="item"
/>
</div>
<div class="form-group">
<label for="time">时间</label>
<input
name="time"
type="text"
class="form-control"
id="time"
/>
</div>
<div class="form-group">
<label for="type">类型</label>
<select name="type" class="form-control" id="type">
<option value="-1">支出</option>
<option value="1">收入</option>
</select>
</div>
<div class="form-group">
<label for="account">金额</label>
<input
name="account"
type="text"
class="form-control"
id="account"
/>
</div>
<div class="form-group">
<label for="remarks">备注</label>
<textarea name="remarks" class="form-control" id="remarks"></textarea>
</div>
<hr>
<button type="submit" class="btn btn-primary btn-block">添加</button>
</form>
</div>
</div>
</div>
<script src="/js/jquery.min.js"></script>
<script src="/js/bootstrap.min.js"></script>
<script src="/js/bootstrap-datepicker.min.js"></script>
<script src="/js/bootstrap-datepicker.zh-CN.min.js"></script>
<script src="/js/main.js"></script>
</body>
</html>
var express =require('express');
var router =express.Router();
//记账本的列表
router.get('/account',function(req, res, next){
res.render('list');
});
//添加记录
router.get('/account/create',function(req, res, next){
res.render('create');
});
//新增记录
router.post('/account',(req, res)=>{
//获取请求体数据
console.log(req.body) //外层app.js已经引入了中间件设置,已将body属性添加到req上
res.send('添加记录')
});
module.exports =router;
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
lowdb的介绍和使用
lowdb这个包,用于持久化数据保存
- 类似于vue中的vuex和pinia的原理
- 包的介绍:Simple to use local JSON database. Use native JavaScript APl to query. Written in TypeScript.
演示lowdb包安装和使用
# 高版本是使用的ES6模块化语法,因此安装低版本1.0.0
npm i lowdb@1.0.0
//导入 lowdb
const low = require('lowdb')
const FileSync = require('lowdb/adapters/FileSync')
// db.json是内部数据存放的文件名称
const adapter = new FileSync('db.json');
//获取 db 对象
const db = low(adapter);
//初始化数据
// db.defaults({ posts: [], user: {} }).write()
//写入数据
// db.get('posts').push({id: 2, title: '今天天气还不错~~'}).write();
// db.get('posts').unshift({id: 3, title: '今天天气还不错~~'}).write();
//获取单条数据
// let res = db.get('posts').find({id: 1}).value();
// console.log(res);
//获取数据
// console.log(db.get('posts').value());
//删除数据
// let res = db.get('posts').remove({id: 2}).write();
// console.log(res);
//更新数据
// db.get('posts').find({id: 1}).assign({title: '今天下雨啦!!!'}).write()
# 写好包的使用逻辑后,执行包的逻辑,即可发现db.json已存入数据
node .\lowdb.js
案例实践记账本-保存账单记录
- 借助lowdb实现保存账单记录
- 借助shortid工具包,实现数据id添加
npm i shortid
var express =require('express');
var router =express.Router();
//导入 lowdb
const low = require('lowdb')
const FileSync = require('lowdb/adapters/FileSync')
const adapter = new FileSync(__dirname + '/../data/db.json');
//获取 db 对象
const db = low(adapter);
//导入 shortid
const shortid = require('shortid');
//记账本的列表
router.get('/account',function(req, res, next){
res.render('list');
});
//添加记录
router.get('/account/create',function(req, res, next){
res.render('create');
});
//新增记录
router.post('/account',(req, res)=>{
//获取请求体数据
console.log(req.body) //外层app.js已经引入了中间件设置,已将body属性添加到req上
//生成 id
let id = shortid.generate();
//写入文件,往数据加入id编号
db.get('accounts').unshift({id:id, ...req.body}).write();
res.send('添加记录')
});
module.exports =router;
案例实践记账本-完善成功提醒
- 类似前面记录页和记账本列表,先往模板页加页面
- 将success.html静态结构,放入模板文件accounts\views\list.ejs
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>提醒</title>
<link
href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.css"
rel="stylesheet"
/>
<style>
.h-50{
height: 50px;
}
</style>
</head>
<body>
<div class="container">
<div class="h-50"></div>
<div class="alert alert-success" role="alert">
<h1>:) 添加成功</h1>
<p>点击跳转</p>
</div>
</div>
</body>
</html>
var express =require('express');
var router =express.Router();
//导入 lowdb
const low = require('lowdb')
const FileSync = require('lowdb/adapters/FileSync')
const adapter = new FileSync(__dirname + '/../data/db.json');
//获取 db 对象
const db = low(adapter);
//导入 shortid
const shortid = require('shortid');
//记账本的列表
router.get('/account',function(req, res, next){
res.render('list');
});
//添加记录
router.get('/account/create',function(req, res, next){
res.render('create');
});
//新增记录
router.post('/account',(req, res)=>{
//获取请求体数据
console.log(req.body) //外层app.js已经引入了中间件设置,已将body属性添加到req上
//生成 id
let id = shortid.generate();
//写入文件,往数据加入id编号
db.get('accounts').unshift({id:id, ...req.body}).write();
//成功提醒
res.render('success', {msg: '添加成功哦~~~', url: '/account'});
});
module.exports =router;
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>提醒</title>
<link
href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.css"
rel="stylesheet"
/>
<style>
.h-50{
height: 50px;
}
</style>
</head>
<body>
<div class="container">
<div class="h-50"></div>
<div class="alert alert-success" role="alert">
<h1>:) <%= msg %></h1>
<p><a href="<%= url %>">点击跳转</a></p>
</div>
</div>
</body>
</html>
案例实践记账本-账单列表数据根据lowdb动态回显
- 之前的账单列表是静态结构,改回动态结构回显
- 修改路由规则记录 accounts\routes\index.js,获取lowdb中的所有的账单信息
var express =require('express');
var router =express.Router();
//导入 lowdb
const low = require('lowdb')
const FileSync = require('lowdb/adapters/FileSync')
const adapter = new FileSync(__dirname + '/../data/db.json');
//获取 db 对象
const db = low(adapter);
//导入 shortid
const shortid = require('shortid');
//记账本的列表
router.get('/account',function(req, res, next){
//获取所有的账单信息
let accounts = db.get('accounts').value();
// res.render('list');
// 改为将数据传递给模板渲染
res.render('list', {accounts: accounts});
});
//添加记录
router.get('/account/create',function(req, res, next){
res.render('create');
});
//新增记录
router.post('/account',(req, res)=>{
//获取请求体数据
console.log(req.body) //外层app.js已经引入了中间件设置,已将body属性添加到req上
//生成 id
let id = shortid.generate();
//写入文件,往数据加入id编号
db.get('accounts').unshift({id:id, ...req.body}).write();
//成功提醒
res.render('success', {msg: '添加成功哦~~~', url: '/account'});
});
module.exports =router;
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<link
href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.css"
rel="stylesheet"
/>
<style>
label {
font-weight: normal;
}
.panel-body .glyphicon-remove{
display: none;
}
.panel-body:hover .glyphicon-remove{
display: inline-block
}
</style>
</head>
<body>
<div class="container">
<div class="row">
<div class="col-xs-12 col-lg-8 col-lg-offset-2">
<h2>记账本</h2>
<hr />
<div class="accounts">
<% accounts.forEach(item => { %>
<div class="panel <%= item.type==='-1' ? 'panel-danger' : 'panel-success' %>">
<div class="panel-heading"><%= item.time %></div>
<div class="panel-body">
<div class="col-xs-6"><%= item.title %></div>
<div class="col-xs-2 text-center">
<span class="label <%= item.type==='-1' ? 'label-warning' : 'label-success' %>"><%= item.type==='-1' ? '支出' : '收入' %></span>
</div>
<div class="col-xs-2 text-right"><%= item.account %> 元</div>
<div class="col-xs-2 text-right">
<a href="/account/<%= item.id %>">
<span
class="glyphicon glyphicon-remove"
aria-hidden="true"
></span>
</a>
</div>
</div>
</div>
<% }) %>
</div>
</div>
</div>
</div>
</body>
</html>
案例实践记账本-账单列表数据删除
需要将服务端对应id数据删掉
- 在路由规则中,创建路由规则,调用lowdb的方法操作
- 通过传参id标识,实现删除对应id数据
- 传参的方式,可以自定义,此案例选用params参数,但将参数拼接到路由后(也可以使用Query 参数)
params传参与query传参区别
- query 用于将请求参数放在 URL 中传递
- 将请求参数作为键值对,用 “?” 符号分隔,放在 URL 的查询字符串中
- params 用于将请求参数放在请求体中传递
- 将请求参数封装成键值对,用逗号分隔,放在请求体的 JSON 或 XML 格式中
- query 用于将请求参数放在 URL 中传递
var express =require('express');
var router =express.Router();
//导入 lowdb
const low = require('lowdb')
const FileSync = require('lowdb/adapters/FileSync')
const adapter = new FileSync(__dirname + '/../data/db.json');
//获取 db 对象
const db = low(adapter);
//导入 shortid
const shortid = require('shortid');
//记账本的列表
router.get('/account',function(req, res, next){
//获取所有的账单信息
let accounts = db.get('accounts').value();
// res.render('list');
// 改为将数据传递给模板渲染
res.render('list', {accounts: accounts});
});
//添加记录
router.get('/account/create',function(req, res, next){
res.render('create');
});
//新增记录
router.post('/account',(req, res)=>{
//获取请求体数据
console.log(req.body) //外层app.js已经引入了中间件设置,已将body属性添加到req上
//生成 id
let id = shortid.generate();
//写入文件,往数据加入id编号
db.get('accounts').unshift({id:id, ...req.body}).write();
//成功提醒
res.render('success', {msg: '添加成功哦~~~', url: '/account'});
});
//删除记录
router.get('/account/:id', (req, res) => {
//获取 params 的 id 参数
let id = req.params.id;
//删除
db.get('accounts').remove({id:id}).write();
//提醒
res.render('success', {msg: '删除成功~~~', url: '/account'});
});
module.exports =router;
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<link
href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.css"
rel="stylesheet"
/>
<style>
label {
font-weight: normal;
}
.panel-body .glyphicon-remove{
display: none;
}
.panel-body:hover .glyphicon-remove{
display: inline-block
}
</style>
</head>
<body>
<div class="container">
<div class="row">
<div class="col-xs-12 col-lg-8 col-lg-offset-2">
<h2>记账本</h2>
<hr />
<div class="accounts">
<% accounts.forEach(item => { %>
<div class="panel <%= item.type==='-1' ? 'panel-danger' : 'panel-success' %>">
<div class="panel-heading"><%= item.time %></div>
<div class="panel-body">
<div class="col-xs-6"><%= item.title %></div>
<div class="col-xs-2 text-center">
<span class="label <%= item.type==='-1' ? 'label-warning' : 'label-success' %>"><%= item.type==='-1' ? '支出' : '收入' %></span>
</div>
<div class="col-xs-2 text-right"><%= item.account %> 元</div>
<div class="col-xs-2 text-right">
<!-- X号绑定id -->
<a href="/account/<%= item.id %>">
<span
class="glyphicon glyphicon-remove"
aria-hidden="true"
></span>
</a>
</div>
</div>
</div>
<% }) %>
</div>
</div>
</div>
</div>
</body>
</html>
附:传参方式的差异
- query 与 params:选择正确的参数传递方式
认识 query 和 params 的概念和作用差异
- 在 HTTP 请求中,query 和 params 都是用于传递请求参数的方式。
但是,它们的作用和使用方式略有不同。
- query:query 用于将请求参数放在 URL 中传递。它将请求参数作为键值对,用 “?” 符号分隔,放在 URL 的查询字符串中。例如,GET 请求中通过 query 传递参数的方法如下:
GET /some/path?param1=value1¶m2=value2 HTTP/1.1
在这个例子中,“?param1=value1¶m2=value2” 就是 query,它将请求参数传递给服务器。
- params:params 用于将请求参数放在请求体中传递。它将请求参数封装成键值对,用逗号分隔,放在请求体的 JSON 或 XML 格式中。例如,POST 请求中通过 params 传递参数的方法如下:
POST /some/path HTTP/1.1
Content-Type: application/json
{
"param1": "value1",
"param2": "value2"
}
在这个例子中,请求体中的 JSON 格式包含了请求参数,它将请求参数传递给服务器。
- 总的来说,query 用于将请求参数放在 URL 中传递,而 params 用于将请求参数放在请求体中传递。
它们的作用和使用方式不同,但都是 HTTP 请求中传递请求参数的重要方式。
理解查询参数(query)的定义和用法
在 URL 中传递参数 使用查询字符串格式
查询参数(query)是指在 URL 中通过键值对的形式传递的参数,它用于在 URL 中增加额外的信息,如查询条件、排序方式、页码等。查询参数的定义和使用方法如下:
定义查询参数:查询参数通常使用键值对的形式定义,键和值之间用 “=” 符号分隔。例如,定义一个查询参数 “page” 的值为 “2”,可以写成 “page=2”。
添加查询参数:在 URL 中添加查询参数的方法是将键值对放在 URL 的查询字符串中,用 “?” 符号分隔。例如,将查询参数 “page” 的值为 “2” 添加到 URL 中,可以写成:
/some/path?page=2
- 获取查询参数:服务器可以通过 URL 中的查询字符串获取查询参数的值。例如,从 URL 中获取查询参数 “page” 的值,可以写成:
page = request.args.get('page')
- 处理查询参数:查询参数可以用于实现各种功能,如查询条件、排序方式、页码等。服务器可以根据查询参数的值来处理请求,并根据处理结果返回相应的响应。
总的来说,查询参数是 URL 中一种重要的参数类型,它用于在 URL 中增加额外的信息,如查询条件、排序方式、页码等。查询参数的定义和使用方法包括定义查询参数、添加查询参数、获取查询参数和处理查询参数等步骤。
理解请求参数(params)的定义和用法
在请求体中传递参数 常见的请求方法:GET、POST、PUT、DELETE
请求参数(params)是指在请求体中通过键值对的形式传递的参数,它用于在请求体中增加额外的信息,如请求数据、查询条件、排序方式等。请求参数的定义和使用方法如下:
定义请求参数:请求参数通常使用键值对的形式定义,键和值之间用 “=” 符号分隔。例如,定义一个请求参数 “data” 的值为 “{‘name’: ‘John’, ‘age’: 30}”,可以写成 “data={‘name’: ‘John’, ‘age’: 30}”。
添加请求参数:在请求体中添加请求参数的方法是将键值对放在请求体的 JSON 或 XML 格式中,用逗号分隔。例如,将请求参数 “data” 的值为 “{‘name’: ‘John’, ‘age’: 30}” 添加到请求体中,可以写成:
Content-Type: application/json
{
"data": {"name": "John", "age": 30}
}
- 获取请求参数:服务器可以通过请求体中的请求参数的值。例如,从请求体中获取请求参数 “data” 的值,可以写成:
data = request.get_json().get('data')
- 处理请求参数:请求参数可以用于实现各种功能,如请求数据、查询条件、排序方式等。服务器可以根据请求参数的值来处理请求,并根据处理结果返回相应的响应。
总的来说,请求参数是请求体中一种重要的参数类型,它用于在请求体中增加额外的信息,如请求数据、查询条件、排序方式等。请求参数的定义和使用方法包括定义请求参数、添加请求参数、获取请求参数和处理请求参数等步骤。
比较 query 和 params 语法和格式的区别
查询参数(query)和请求参数(params)都是用于在 HTTP 请求中传递参数的方式,但它们在语法和格式上有所不同。
语法:查询参数使用 URL 中的查询字符串传递参数,参数之间用 “&” 符号分隔。请求参数使用请求体中的
JSON
或XML
格式传递参数,参数之间用逗号分隔。格式:查询参数的格式通常为 “key=value”,请求参数的格式通常为 “key: value”。
作用:查询参数主要用于传递 URL 中的查询条件,如搜索关键字、排序方式等。请求参数主要用于传递请求体中的请求数据,如用户信息、商品信息等。
总的来说,查询参数和请求参数都是 HTTP 请求中传递参数的重要方式,但它们在语法和格式上有所不同。查询参数主要用于 URL 中的查询条件,请求参数主要用于请求体中的请求数据。
query 参数使用键值对表示,以问号开头,用&连接多个参数 params 参数可以是键值对、数组或对象,根据请求方法的不同,以不同的方式传递
比较 query 和 params 功能和用途的差异
query 和 params 都是 HTTP 请求中传递参数的方式,但它们在功能和用途上有所不同。
功能:query 主要用于传递 URL 中的查询条件,如搜索关键字、排序方式等。而 params 主要用于传递请求体中的请求数据,如用户信息、商品信息等。
用途:query 主要用于服务器端处理请求,并返回响应。而 params 主要用于客户端向服务器端发送请求,以实现特定的功能。
总的来说,query 和 params 都是 HTTP 请求中传递参数的重要方式,但它们在功能和用途上有所不同。query 主要用于服务器端处理请求,而 params 主要用于客户端向服务器端发送请求。
query 参数主要用于获取数据,如分页、筛选等 params 参数更适合用于修改数据、传递复杂的实体信息
使用场景和示例
query 和 params 都是 HTTP 请求中传递参数的方式,但它们在场景和示例上有所不同。
- query 使用场景:query 主要用于传递 URL 中的查询条件,如搜索关键字、排序方式等。例如,在搜索商品时,可以使用 query 传递搜索关键字,如:
GET /products?search=smartphone
- params 使用场景:params 主要用于传递请求体中的请求数据,如用户信息、商品信息等。例如,在注册用户时,可以使用 params 传递用户信息,如:
POST /users
{
"name": "John",
"email": "john@example.com",
"password": "password"
}
总的来说,query 和 params 都是 HTTP 请求中传递参数的重要方式,但它们在场景和示例上有所不同。query 主要用于传递 URL 中的查询条件,而 params 主要用于传递请求体中的请求数据。
最佳实践和注意事项
参数命名规范:参数名称应该清晰、易于理解,遵循驼峰命名法或下划线命名法等规范。
参数格式化和校验:在客户端对参数进行格式化时,确保参数的格式符合服务器的预期。同时,在服务器端对参数进行校验时,确保参数的有效性和安全性。
避免 SQL 注入等安全问题:在客户端对参数进行格式化时,使用参数化查询或预处理语句等方式,避免 SQL 注入等安全问题。在服务器端对参数进行校验时,确保参数的有效性和安全性。
总的来说,query 和 params 最佳实践和注意事项在于命名规范、格式化和校验参数,以及避免 SQL 注入等安全问题。遵循这些最佳实践和注意事项,可以确保 HTTP 请求中的参数传递更加高效、安全和可靠。
总结 query 和 params 的特点和应用场景
query 和 params 都是 HTTP 请求中传递参数的方式,但它们在语法、格式、功能和用途上有所不同。
- 特点:
- query:使用 URL 中的查询字符串传递参数,参数之间用 “&” 符号分隔。
- params:使用请求体中的 JSON 或 XML 格式传递参数,参数之间用逗号分隔。
- 应用场景:
- query:主要用于传递 URL 中的查询条件,如搜索关键字、排序方式等。
- params:主要用于传递请求体中的请求数据,如用户信息、商品信息等。
总的来说,query 和 params 都是 HTTP 请求中传递参数的重要方式,但它们在语法、格式、功能和用途上有所不同。query 主要用于传递 URL 中的查询条件,而 params 主要用于传递请求体中的请求数据。