学习内容
- express框架的使用方式
- 静态资源托管
- get请求接口
- post请求接口
- 中间件
- 文件上传 multer
- string-random 随机字符串
- express中的路由管理方式
- cookie和session
- 跨域
- cors
- jsonp
- 数据库
- 基本语句
- 使用 nodejs 操作数据库
- 异步操作管理
- promise
- async await
express 框架的使用方式
- 静态资源托管
- 默认根目录访问时的托管
app.use(express.static(path.join(__dirname, '书写一个目录名即可')))
- 自定义地址的托管
app.use('用来设置访问时的url' ,express.static(path.join(__dirname, '书写一个目录名即可')))
- 默认根目录访问时的托管
- 设置 get 请求接口
- 基本格式:app.get(请求地址, 回调函数)
- 回调函数内部接收req和res与node中是一样的
- req.query可以直接接收get请求参数的对象结构,无需借助其他模块进行转换
- 响应方式:res.send() 通用功能,发送中文不会乱码,因为express设置了默认响应头为 text/html;charset=utf-8,发送对象会自动转换为JSON格式的字符串,会设置响应头为 application/json;charset=utf-8
- 基本格式:app.get(请求地址, 回调函数)
- 设置 post 请求接口
- 基本格式:app.post(请求地址, 回调函数)
- express中没有直接进行post请求参数的处理操作,需要使用与express相关的包进行post请求参数的处理操作使用的包名为
body-parser
, 下载express时已经自动下载完毕了,可以直接进行引入操作 - 引入方式:const bodyParser = require('body-parser');
- 让app使用bodyParser的功能进行req.body的设置
- app.use(bodyParser.urlencoded({extended: false}));
- false表示使用内置模块querystring进行处理,true为默认值使用第三方模块qs处理
- 可以在app.post()的回调函数中直接使用req.body进行请求体的操作
- app.use(bodyParser.urlencoded({extended: false}));
- 中间件
- 统一的中间件设置方式(所有请求都经过这个中间件的处理)
app.use((req, res, next) => { // req和res与之前的所有req和res是一样的 // next() 调用时,可以让请求继续触发后续的操作(中间件、请求处理) // - 如果没有调用next,请求就不会继续向后执行 // - app.use(express.static(...)); 内部没有设置next,后续的请求处理就没有意义了 });
- 指定接口地址进行中间件设置
app.use('/common/post指定的接口名', (req, res, next) => {
// 只有这个指定的接口会经过这个中间件的处理
// - app.use('地址', express.static(...));
});
* 自定义的内部处理
* 可以自己在app.use的回调函数中进行条件判断
* 通过条件的执行中间件功能
* 不通过的直接设置next()
文件上传 multer 模块
- 使用了multer中间件
- 安装:npm i multer
- 使用步骤:
- 引入
- 配置multer相关信息
- multer({ dest: '地址' }); // 简略处理方式
- 详细配置,上传地址,上传文件名等
let upload = multer({ storage: multer.diskStorage({ destination: (req, file, callback) => { callback(null, '绝对路径形式的地址'); // callback的参数 // - 参数1:是错误信息,如果设置了,就没法正常保存了,写null即可 // - 参数2:是保存的位置,绝对路径 }, filename: (req, file, callback) => { callback(null, '文件名称'); // callback的参数 // - 参数1:是错误信息,如果设置了,就没法正常保存了,写null即可 // - 参数2:是保存的位置,绝对路径 // - 可以使用string-random进行随机文件名称的生成 }, }) }); // 在接口中调用upload.single('文件域的name值') app.post('接口地址', upload.single('name值'), (req, res) => { // req.file用来查看上传后的文件的信息 // console.log(req.file); res.send('ok'); });
- string-random 模块
- 下载并引入: const sr = require('string-random')
- 使用 sr() 或 sr(随机字符串长度),默认 8 位
express中的路由管理方式
编程中的路由指的是 对 ‘客户端到服务端的请求’ 进行处理的一种方式
例如:客户端通过 /common/post 发送请求,服务端对 /common/post进行处理,这就是设置了一个路由操作。(其实就是设置了一个接口,一个接口就可以称为是一个路由)
- 基本的路由设置方式:
- app.get(地址,回调);
- app.post(地址,回调);
- express 中的路由管理:方便模块化编程,减少代码都在一个文件的问题
- 使用方式:
- 将某部分路由功能放到一个单独的模块中保存
- 通过let router = express.Router()创建一个路由管理器实例
- router的使用方式与app相同
- 通过 module.exports = router 方式进行导出/暴露
- 通过let router = express.Router()创建一个路由管理器实例
- 从server.js中进行模块的引入
- 通过app.use()以中间件方式使用路由模块的功能
let uesrRouter = require('./router/userRouter.js'); app.use('/user', userRouter);
- 注意:userRouter模块内部设置具体路由时,就不要再写 /user的部分了
- 将某部分路由功能放到一个单独的模块中保存
- 使用方式:
cookie和session
http是一种无状态的协议:
每次客户端请求服务端时,都是'初次见面'
cookie
- cookie在登录中的设置方式:
- 问题:服务端每次接受用户的请求时,用于http无状态,所以无法确定用户的身份
- 为了解决这个无状态的问题,会在登录成功时,服务端给用户下发cookie的数据(小票)
- cookie的数据是保存在客户端的
- 等以后用户再请求服务端时,带着小票一起发送过去(自动),服务端检测小票的信息即可判断这个用户使用访问过
- 操作方式:
- 设置方式:
- res.cookie();
- 参数1:cookie 数值的名称
- 参数2:cookie 数值的值
- 参数3:配置信息,对象
- expires 过期时间:值为
new Date(Date.now() + 1000 * 60 * 60 * 24 * 7)
- expires 过期时间:值为
- res.cookie();
- 获取方式:
- req.headers.cookie 原生写法,获取的是字符串结构不好用
- 使用中间件cookie-parser
- 安装并引入并调用
- let cp = require('cookie-parser');
- app.use(cp());
- 这个中间件给req设置了cookies属性,可以访问对象形式的cookie数据
- 安装并引入并调用
- 清除方式
- res.clearCookie('cookie数据的名称');
- 设置方式:
- express中的重定向方式
- res.redirect('重定向到哪个地址');
- 注意:设置重定向后不用再进行res.send()操作
- res.redirect('重定向到哪个地址');
session
session不是一个新技术,实际上就是cookie的一种使用方式
- session实现方式:
- 因为cookie是保存在客户端的,用户可以随意修改或伪造
- 服务端不再将数据直接下发到客户端保存了,而是将数据保存在服务端
- 下发的是保存数据区域的标识(手牌)
- 用户下次请求时带着标识到服务端,开箱子读取数据进行操作即可
- 好处:确保数据无法被用户操作,安全
- 设置方式
- 使用了express-session中间件
- 下载并引入:let es = require('express-session');
- 引入中间件并进行设置:
app.use(es({secret: 'helloworld'}))
- 读写操作
- req.session 是一个对象,可以进行读写操作
- req.session.destroy() 清除session数据
- 注意:服务端清除了session数据后,客户端存储的session标记不会被清除,也没用了
// 设置 session 会话处理
app.use(es({
secret: 'test',
cookie: {
// 1 分钟后失效
maxAge: 1000 * 60,
}
}))
app.use((req, res, next) => {
// 刷新 session 的有效期
req.session._garbage = Date();
req.session.touch();
next();
})
跨域
同源策略
同源策略是浏览器自带的一种安全机制。
本质上就是浏览器不允许我们使用ajax进行非同源地址的访问
- 同源地址:
- 指的是三个部分相同的地址
- 协议
- 域名
- 端口
- 但是因为现在的网站功能非常丰富,经常出现一个公司的网站有很多域名的情况
- 这时就需要我们能够突破浏览器的同源策略限制,这种操作称为 跨域
- 指的是三个部分相同的地址
CORS 跨域方式(IE10以上)
* cross origin resource sharing 跨域资源共享
// 如果我们希望这个接口可以被任意的其他非同源地址用ajax请求,可以设置一个响应头
// - 设置为*表示随便访问
// res.header('Access-Control-Allow-Origin', '*');
// - 设置为指定地址可以让指定地址访问
// res.header('Access-Control-Allow-Origin', 'http://localhost:5000');
// - 如果希望设置多个源都可以访问,一定不能覆盖设置
// - 1 通过req.headers.origin接收当前源的地址
// - 2 自己进行检测
let arr = ['http://localhost:5000', 'http://localhost:6666', 'http://localhost:7777'];
let index = arr.indexOf(req.headers.origin); // arr.includes()
if (index !== -1) {
res.header('Access-Control-Allow-Origin', req.headers.origin)
}
JSONP
- 是一种传统的跨域解决方案
- JSONP不是规范中提出了跨域方式,而是开发者通过实践得到的一种解决方法
- 随着规范的不断完善,推出了CORS的跨域解决方案
- JSONP不是规范中提出了跨域方式,而是开发者通过实践得到的一种解决方法
- 使用场景:
- CORS公司内部进行使用
- JSONP会在我们请求第三方接口时常用
- 什么是JSONP
- 因为浏览器的同源策略限制了ajax的
请求,JSONP就不采用ajax进行请求操作了 - json with padding 常用的数据格式为JSON,所以JSONP中通常也传递的是JSON,所以起名叫JSONP
- 因为浏览器的同源策略限制了ajax的
- 设置方式:
- 原生的设置方式:
- 客户端的处理方式
- 设置script标签,将src设置为接口地址
- 通过callback参数传递客户端的处理函数名称
- 在这个请求发送前设置好对应的处理函数即可
- 服务端的处理方式:
- 服务端接收处理函数名称
- 响应函数调用形式的字符串,并传入数据即可
- 客户端的处理方式
- jQuery的设置方式:
- 在jQuery的ajax方法中设置一个dataType属性,值为'jsonp'
- axios不支持JSONP
- 原生的设置方式:
- JSONP的特点:
- 没有兼容性问题
- 只能发送get请求
数据库
基本语句
- 查询语句
1 注释写法
-- 这里是注释的内容
2 sql语句的使用
2.1 select语句 - 用来进行数据的查询操作(获取数据库中的数据)
-- select 字段名 from 表名
select * from user 获取user表中的所有数据
select id from user 获取某个字段的数据
select id,username,userage from user 获取多个字段的数据
-- where子句的使用
select * from user where id=1 指定条件
select * from user where id in (1,2) 指定某个字段的多个情况
select * from user where id>1 and userage=22 指定多个条件
select * from user where id>1 or userage=18 多个条件满足某个
-- order by子句的使用
select * from user order by 字段名 根据指定字段排序,默认升序
select * from user order by userage
select * from user order by 字段名 desc 根据指定字段排序,降序
select * from user order by userage desc
-- limit 限制
select * from user limit 2 只要最前面2条
select * from user limit 0,3 后面的第一个值就像slice的参数一样,索引值, 第二个是个数
- 分页数据的读取方式: 如果每页获取3条 (了解)
select * from user limit 0,3 第一页
select * from user limit 3,3 第二页
select * from user limit 6,3 第三页
select * from user limit 9,3 第四页
select * from user limit (page-1) * 3, 3 第page页
- 增删改
- insert into
2.2 insert into 用来进行数据的新增操作(下面的多种操作方式,随意掌握一个即可) insert into 表名 (字段名) values(数据...) insert into user (userage,username) values(17, 'jack') 指定字段设置值时,必须与名称顺序对应 insert into user values(null,'吴悠',13) 不指定字段,设置值时必须按照表格顺序设置,不填的写null 下面是同时设置多条的书写方式: insert into user values(null,'吴悠1',12),(null,'吴悠2',11),(null,'吴悠3',10) insert into user (userage,username) values(127, 'jack1'),(137, 'jack2'),(147, 'jack3') insert into user set username='rose2', userage=19
- delete 和 update
2.3 delete 用来进行数据删除
delete from user; 删除user表中所有数据,不要轻易尝试
通常delete都与where子句结合使用 (之前使用的where操作与这里是一样的)
delete from user where id=12 指定条件删除数据
delete from user where id in (2,5,14)
2.4 update 更新数据(修改)
update 表名 set 字段名=值; 更新指定表中的所有数据,不要轻易尝试
通常update都与where结合使用
update user set username='abc' where id=3
update user set username='xyz',userage=36 where id in (3,4)
通过nodejs操作数据库的方式
- 使用一个mysql的包进行数据库操作,安装的这个mysql包,是让nodejs方便的操作mysql数据库使用的
- 安装方式: npm install mysql
- 基本使用方式:
- 引入: const mysql = require('mysql');
- 创建连接对象:
const con = mysql.createConnection({ host: 'localhost', // 主机地址,主机名 user: 'root', // 用户名 password: 'root', // 密码 port: '3306', // 端口号 database: 'demo' // 数据库名 });
- con.query()
- 参数1必选,sql语句
- 参数2可选:占位符的数据(可以选择性记忆)
- 参数3必选:回调函数
- 参数1 err错误信息
- 参数2 result
- 如果是select操作,result是获取到的数据,数组格式
- 如果是非查询操作,result是操作结果的对象形式的信息
- affectedRows 代表受影响的行数,应当进行检测
- 数据库对比json文件的好处
- json文件可以随便操作,数据库有用户名和密码,更安全一些
- json文件需要自己书写js代码进行数据操作,数据库有sql语句,操作更方便简洁
异步操作管理
为什么要进行异步操作的管理
- 异步操作都会有回调函数
- 回调一层一层嵌套的写法用一个特殊的称呼:回调地狱
- 会出现各种的嵌套操作
- 嵌套写法:
const fs = require('fs'); // 需求:按顺序依次读取3个json文件,并输出内容 // 1 第一次读取 fs.readFile('./1.json', 'utf-8', (err, data) => { if (err) { throw err; } console.log(data); // 输出文件内容 // 2 第二个文件读取 fs.readFile('./2.json', 'utf-8', (err, data) => { if (err) { throw err; } console.log(data); // 输出文件内容 // 3 第三个文件读取 fs.readFile('./3.json', 'utf-8', (err, data) => { if (err) { throw err; } console.log(data); // 输出文件内容 }); }); });
promise
目的:通过promise的处理,让异步操作书写的像同步代码一样,不需要书写多层的嵌套结构
- 使用方式
- new Promise()
- 参数为回调函数
- 参数1是用来触发then()的函数
- 参数2是用来触发catch()的函数
- 参数为回调函数
- promise实例对象有3个方法
- then() catch() finally()
- new Promise()
- 解决上面的示例问题
- 好处:可以让多次异步操作不需要书写为嵌套结构
- 书写形式为链式写法(同步写法)
// 将读取文件功能进行封装
function readFile(path) {
// 将当前读取文件的promise对象返回
return new Promise((ok, err) => {
// 在promise中进行异步操作设置
fs.readFile(path, 'utf-8', (error, data) => {
// 如果有错误产生,触发catch
if (error) {
// 调用err()
err('读取文件错误');
} else {
// 成功时调用ok()触发then()
ok(data);
}
})
});
}
// 进行多次异步的文件读取操作
// - 当给then()设置的返回值是promise对象,这个对象会成为then的返回值
readFile('./1.json')
.then((data) => {
// 第一次文件读取
console.log(data); // 第一次输出
// 希望读取第二次文件
return readFile('./21.json')
})
.then((data) => {
console.log(data); // 第二次输出
// 希望读取第三次文件
return readFile('./3.json');
})
.then((data) => {
console.log(data); // 第三次输出
})
.catch((err) => {
console.log(err);
});
async await
ES6认为promise的.then() .catch()还是有些麻烦,又推出了一种新的写法,用来简化
// 使用async和await时,只需要设置ok的调用即可
function readFile(path) {
return new Promise((ok, err) => {
fs.readFile(path, 'utf-8', (error, data) => {
// 无论成功还是失败都触发ok
if (error) {
ok(null); // 失败时传入一些错误信息
} else {
ok(data); // 成功时传入数据
}
})
});
}
// --- 下面的是常用的写法:
// 1 后续我们设置一个async函数
async function myFun() {
// 2 调用可以返回promise对象的函数readFile()
// - 调用前设置await
let data1 = await readFile('./1.json');
// console.log(data1); // 可以根据data1的结果进行ifelse判断
let data2 = await readFile('./2.json');
console.log(data2);
let data3 = await readFile('./3.json');
console.log(data3);
}
myFun();
内事不懂问百度,外事不懂问谷歌~