目录
Nodejs创建web服务器(不常用)
创建服务器步骤
搭建过程中需要的
Express框架开发
基本信息
express的安装和使用
初始化项目并安装express
初体验:express创建web服务器
express中的app对象
1.app.get( 路径,兼听函数 )
2.app.post(路径,兼听函数 )
3. app.all(路径,兼听函数 )
express的response对象
1. res.send( 字符串|对象 )。
2.res.sendFile( absolute filepath )
express的request对象
1)req.query
2)req.params
使用步骤
开发工具的使用(nodemon热更新 ,Rest Client )
nodemon热更新工具
Rest Client
路由Router
什么是路由?
express中Router的作用?以及Router要解决的问题?
Express中的路由(Node的路由)
匹配流程
express.Router 模块化路由
总结(原生nodejs和express的req,res)
express的中间件
什么是中间件?
简介
中间件的好处
中间件执行流程
使用中间件
中间节的基本使用
用法一:app.use()
用法二:router.use()
中间件加前缀
用法一:app.use(前缀,中间件函数):使用自定义中间件时
用法二:app.use(前缀,中间件函数):使用模块化路由时 【重点】
用法三:router.use(前缀,中间件函数):使用自定义中间件时
中间件种类
应用级别的中间件
错误中间件
逻辑错误 :就是含有err,req,res,next四个形参的自定义中间件
内置中间件
开放静态资源:express.static(绝对路径)
接收post参数
1)、express.urlencoded()内置中间件用来接收以post方式的键值对格式发送的参数:
2)、express.json()内置中间件用来接收以post方式的json格式发送的参数:
第三方中间件
小图标
图片验证码
为什么要创建web服务器?
只有我们把nodejs程序通过web服务器发布出去之后,别人才能通过互联网来访问我们的nodejs程序,否则也只是在本地运行我们的nodejs程序。
//引入http模块
const http = require('http');
// console.log(http);
//创建web服务器:
const server = http.createServer();
// console.log(server);
//监听事件:server.on('事件名',回调方法);
//req对象:request请求对象
//res对象:response响应对象
server.on('request', function(req, res) {
res.end('Yes OK');
// res.end('Hello web'); //结束响应、res.end()必须且只能使用一次
});
//监听端口:
server.listen(3000, function() {
console.log('3000端口');
});
设置响应头信息。res.writeHead(200,{'Content-Type':"text/html;charset=utf8"});
打印请求消息。method和url
//引入http模块
const http = require('http');
// console.log(http);
//创建web服务器:
const server = http.createServer();
// console.log(server);
//监听事件:server.on('事件名',回调方法);
//req对象:request请求对象
//res对象:response响应对象
server.on('request', function(req, res) {
console.log(req.url);
//res.setHeader()或res.writeHead():设置响应的头信息
// res.setHeader('content-type', 'text/html;charset=utf-8');
res.writeHead(200, 'ok', { 'content-type': 'text/html;charset=utf-8' });
res.write('张三
'); //返回响应的内容、res.write()可以多次使用
res.write('年龄:20
');
res.end('Yes OK');
// res.end('Hello web'); //结束响应、res.end()必须且只能使用一次
});
//监听端口:
server.listen(3000, function() {
console.log('3000端口');
});
Express是基于基于 Nodejs平台,快速、开放、极简的 Web 开发框架(后端开发框架)。
中文地址:Express - 基于 Node.js 平台的 web 应用开发框架 - Express 中文文档 | Express 中文网https://www.expressjs.com.cn/
官网地址:Express - Node.js web application framework
作用:使用 Express,我们可以方便、快速的创建 Web 网站的服务器或 API 接口(纯json数据)的服务器。
本质上:express是一个第三方包存在于npm社区中。
API(Application Programming Interface,应用程序接口)是一些预先定义的接口(如函数、HTTP接口),或指软件系统不同组成部分衔接的约定。
注意:在项目根目录下执行下面的命令:
npm i express
//引入express框架
const express = require('express');
// console.log(express);
//创建应用:
const app = express();
// console.log(app);
//监听端口:
app.listen(4040, () => {
console.log('4040端口');
});
注意:所有的路径必须以/开头
匹配以get方式发送过来的请求
以get方式发送请求的有:
1)、在浏览器地址栏中;
2)、a标签中的href属性;
3)、form标签中的method='get'或省略method属性; //只能以get方式的查询字符串格式发送参数
4)、javascript中使用location.href进行页面跳转;
注意:所有的路径必须以/开头
匹配以post方式发送过来的请求
匹配以任意方式发送过来的请求,app.all()方法通常放在最后面来处理404错误。
返回响应,res.send()方法相当于原生nodejs中的res.setHeader()和res.end()这两个方法
将某个文件的内容读取出来并作为响应返回给客户端。
req.query属性用来接收get方式的查询字符串格式发送的参数,get方式的查询字符串格式的参数如下:
http://localhost:4040/teacher?参数名=参数值&参数名2=参数值2
专业名称:动态路径(路由)
req.params属性用来接收get方式的path路径格式发送的参数,get方式的path路径格式的参数如下:http://localhost:4040/zhuce/参数值1/参数值2/参数值3
第一步:使用app.get()设置路径时参数部分要使用:变量名来表示,如:
//详情页面
//app.get('/detail/:变量名1/:变量名2', (req, res) => {
//
// res.send(`详情页`);
//});
//详情页面
app.get('/detail/:uid/:email', (req, res) => {
console.log(req.params);
let { uid = '', email = '' } = req.params;
res.send(`详情页${uid} ${email}`);
});
如果以热更新方式运行某个应用程序,则热更新会检查当前应用程序文件的代码是否发生变化,若有变化则热更新工具会自动停止并重新运行当前应用程序,而不需要手动频繁停止、运行某个应用程序。
第一步:安装nodemon热更新工具:
在dos小黑窗的任意目录中执行下面的命令:
npm i nodemon -g
关于-g参数的说明: 【重点】
1)、使用-g参数安装的第三方包默认存储在:C:\Users\当前用户\AppData\Roaming\npm;
2)、使用-g参数安装某个包时可以在dos小黑窗的任意目录来执行安装命令,而不一定要在项目的根目录中执行安装命令;
3)、同一台电脑只需要安装一次即可;
第二步:以热更新方式来运行某个应用程序:
E:\web_beijing\day07\代码>nodemon 5-作业-zhuce.js
Rest Client是vscode的一个插件,该插件是用来模拟HTTP协议中的各种请求方式发送请求的,通常用来调试服务端的接口程序。
第一步:在vscode工具中安装Rest Client插件;
第二步:在任意目录中创建以.http结尾的文件,在这个以.http结尾文件中定义要调用的服务端程序(接口程序),格式如下:
@urls=http://localhost:5000
POST {{urls}}/mytest HTTP/1.1
###
GET {{urls}}/[email protected] HTTP/1.1
###
GET {{urls}}/login/110/zhangsan HTTP/1.1
广义上来讲,路由就是映射关系。对于我们网络请求中的路由是:每一次请求对应每一个请求处理的函数。
路由就是根据请求中的不同path路径返回不同的响应,在express框架中设计路由的方式有两种:
第一种:使用app.get()、app.post()、app.all()方法来设计路由;
第二种:使用模块化方式来设计路由;
(1): express.Router 可以认为是一个微型的只用来处理中间件与控制器的 app, 它拥有和 app 类似的方法,例如 get、post等等。
(2): router它解决了直接把 app 暴露给其它模块使得 app 有被滥用的风险
app.method( path,callback )
参数说明:
method:代表请求方式,比如get,post
path:代表请求路径
callback:代表回调函数,用户请求匹配到路由以后要做的事情。
为什么要采用模块化路由?
因为使用app.get()、app.post()、app.all()来设计路由时会把所有路由都混在一起,后期维护不方便。
采用模块化路由的语法来设计路由的步骤: 【重点】
第一步:新建模块化路由文件user.js,并在文件中设计路由,user.js文件中的语法格式为:
const express = require('express');
const router = express.Router();
//设计路由:router.get()、router.post()、router.all()
//暴露router对象:
module.exports = router
第二步:使用上面定义好的模块化路由文件user.js,代码如下:
注意:使用模块化路由定义的路由: app.use([路径,]回调方法);
const express = require('express');
const app = express();
app.listen(5000, () => {
console.log('5000端口');
});
//引入采用模块化路由语法定义的路由文件
let userRouter = require('./user.js');
// console.log(userRouter);
//使用模块化路由语法定义的路由:app.use([路径,]回调方法);
app.use(userRouter);
总结:
原生nodejs的res对象上的方法:
res.setHeader()、res.writeHead():设置响应的头信息
res.write():设置要返回的响应数据,可以多次使用
res.end():结束响应,必须且只能使用一次
原生nodejs的req对象上的方法:
req.url:获取请求的完整URL地址
express框架的res对象上的方法:
res.send(字符串|json对象):设置要返回的响应数据,相当于原生nodejs中的res.setHeader()和res.end()这两个方法,不能同时执行多次res.send()方法。
res.sendFile(文件的绝对路径):将某个文件内容读取出来并作为响应返回给客户端;
express框架的req对象上的属性:
req.query:接收get方式的查询字符串格式发送的参数;
req.params:接收get方式的path路径格式发送的参数;
中间件就是在接收请求之后返回响应之前要执行的函数,而这些函数有一定的业务处理能力,可以理解中现实生活中的车间。
express的中间件分为:自定义中间件、内置中间件、第三方中间件;
中间件(Middleware),特指业务流程的中间处理环节。我们可以把中间件比作工厂中的车间。比如:在处理铁矿石的时候,一般都要经过三个处理环节,从而保证处理过后的矿石达到标准的钢材。处理铁矿石的这三个中间处理环节,就可以叫做中间件。而中间件其实是路由的升级,也能达到请求的匹配,只不过必须要进行下一步处理,以到达最终的路由匹配,就像在工厂中生产产品,最后必须要出厂。
中间件机制使得Web应用具备良好的可扩展性和组合性。
1、会使用中间层作为数据的中转站(解决跨域)
好处:
1,没有跨域
2、可以对接收的数据进行二次处理。(过滤) 小程序 ,公众号,工作项目
当一个请求到达Express的服务器之后,可以连续调用多个中间件,从而对这次请求进行预处理。但是必须要有一个最终的匹配路由进行响应给客户端结果。
app.use( [前缀,]中间件函数 )
router.use([前缀,]中间件函数)
中间件要注意的事项:【重点】
1)、使用中间件的代码通常会放在所有路由的最前面;
2)、在自定义中间件内部当所有的业务代码执行完成后,要手动调用next()方法;
3)、next()方法会查找并执行后面能匹配上的路由;
4)、根据实际情况可以连续执行多个中间件;
5)、当中间件内部的业务代码出现异常时则通常会把异常信息当作next()方法的参数,则next()方法默认会把异常信息直接输出到屏幕上,如果需要对next()方法中的参数进行二次处理时则需要定义含err,req,res,next四个形参的逻辑错误处理中间件;
const experss = require('express');
const timestamp = require('time-stamp');
const app = experss();
app.listen(3000, () => {
console.log(`web服务器工作在3000端口`);
});
//req:request请求对象
//res:response响应对象
//next:next()为方法
function getCurTimes(req, res, next) {
// console.log(req, res, 222);
// console.log(next, 1111);
//生成日期时间
let curtimes = timestamp('YYYY-MM-DD HH:mm:ss');
req.tiems = curtimes;
res.t = curtimes;
// console.log(curtimes, 999);
next(); //next()方法查找并执行后面能匹配上的路由
}
function myDemo(req, res, next) {
console.log('Hello web');
next();
}
//使用中间件语法:
app.use(getCurTimes);
// app.use(myDemo);
//老师界面:
app.get('/teacher', (req, res) => {
res.send(`这是老师的界面:${req.tiems} ${res.t}`);
});
// app.use(getCurTimes);
//学生界面:
app.get('/student', (req, res) => {
res.send(`学生界面:${req.tiems}`);
});
模块化路由文件index.js的代码如下:
//模块化路由语法来设计路由:
const express = require('express');
const router = express.Router();
//定义中间件函数:
function myTest(req, res, next) {
console.log('Hello WEB');
next();
}
router.use(myTest);
router.get('/banners', (req, res) => {
res.send('轮播图');
});
router.post('/mycourse', (req, res) => {
res.send('首页同步课程');
});
module.exports = router;
在app.js文件中使用上面定义的模块化路由,代码如下:
const experss = require('express');
const app = experss();
app.listen(5000, () => {
console.log(`web服务器工作在5000端口`);
});
let indexRouter = require('./3-index.js');
app.use(indexRouter);
const experss = require('express');
const timestamp = require('time-stamp');
const app = experss();
app.listen(3000, () => {
console.log(`web服务器工作在3000端口`);
});
// let obj = {};
// obj.x = 11;
// console.log(obj);
//req:request请求对象
//res:response响应对象
//next:next()为方法
function getCurTimes(req, res, next) {
// console.log(req, res, 222);
// console.log(next, 1111);
if (1) { //正常
let curtimes = timestamp('YYYY-MM-DD HH:mm:ss');
req.tiems = curtimes;
res.t = curtimes;
// console.log(curtimes, 999);
next(); //next()方法查找并执行后面能匹配上的路由
} else { //异常
next('这是错误信息');
}
}
function myDemo(req, res, next) {
console.log('Hello web');
next();
}
//使用中间件语法:
// app.use(getCurTimes);
app.use('/student', getCurTimes);
// app.use(myDemo);
//老师界面:
app.get('/teacher', (req, res) => {
res.send(`这是老师的界面:${req.tiems} ${res.t}`);
});
// app.use(getCurTimes);
//学生界面:
app.get('/student', (req, res) => {
res.send(`学生界面:${req.tiems}`);
});
//逻辑错误处理中间件:
function proErrors(err, req, res, next) {
console.log(err, 1111);
// fs.writeFileSync(path.join(__dirname,'err.log'));
res.send(`出错了:${err}`);
}
app.use(proErrors);
注意:3-index.js这个模块化路由文件中的所有路由路径以/api开头
const experss = require('express');
const app = experss();
app.listen(5000, () => {
console.log(`web服务器工作在5000端口`);
});
let indexRouter = require('./3-index.js');
// app.use(indexRouter);
//注意:3-index.js这个模块化路由文件中的所有路由路径以/api开头
app.use('/api', indexRouter);
//模块化路由语法来设计路由:
const express = require('express');
const router = express.Router();
//定义中间件函数:
function myTest(req, res, next) {
console.log('Hello WEB');
next();
}
router.use('/mycourse', myTest);
router.get('/banners', (req, res) => {
res.send('轮播图');
});
router.post('/mycourse', (req, res) => {
res.send('首页同步课程');
});
module.exports = router;
app.get
app.post
404错误:
注意:404错误中间件要放在所有路由的最后面
用法一:在模块化路由文件中定义
//模块化路由语法来设计路由:
const express = require('express');
const path = require('path');
const router = express.Router();
//定义中间件函数:
function myTest(req, res, next) {
console.log('Hello WEB');
next();
}
router.use('/mycourse', myTest);
router.get('/banners', (req, res) => {
res.send('轮播图');
});
router.post('/mycourse', (req, res) => {
res.send('首页同步课程');
});
function err404(req, res, next) {
// res.send('404错误');
res.sendFile(path.join(__dirname, '404.html'));
}
router.use('*', err404);
// router.use('*', (req, res, next) => {
// res.send('404错误');
// });
module.exports = router;
用法二:使用app对象上的use()方法
const experss = require('express');
const timestamp = require('time-stamp');
const app = experss();
app.listen(3000, () => {
console.log(`web服务器工作在3000端口`);
});
// let obj = {};
// obj.x = 11;
// console.log(obj);
//req:request请求对象
//res:response响应对象
//next:next()为方法
function getCurTimes(req, res, next) {
// console.log(req, res, 222);
// console.log(next, 1111);
if (1) { //正常
let curtimes = timestamp('YYYY-MM-DD HH:mm:ss');
req.tiems = curtimes;
res.t = curtimes;
// console.log(curtimes, 999);
next(); //next()方法查找并执行后面能匹配上的路由
} else { //异常
next('这是错误信息');
}
}
function myDemo(req, res, next) {
console.log('Hello web');
next();
}
//使用中间件语法:
// app.use(getCurTimes);
app.use('/student', getCurTimes);
// app.use(myDemo);
//老师界面:
app.get('/teacher', (req, res) => {
res.send(`这是老师的界面:${req.tiems} ${res.t}`);
});
// app.use(getCurTimes);
//学生界面:
app.get('/student', (req, res) => {
res.send(`学生界面:${req.tiems}`);
});
//逻辑错误处理中间件:
function proErrors(err, req, res, next) {
console.log(err, 1111);
// fs.writeFileSync(path.join(__dirname,'err.log'));
res.send(`出错了:${err}`);
}
app.use(proErrors);
注意:将某个目录开放之后在访问时不需要带上该目录名称
中文文档参考地址:利用 Express 托管静态文件 - Express 中文文档 | Express 中文网
什么是开放静态资源?
就是让用户通过我们的web服务器来访问静态资源(比如:.js文件、.css文件、.html文件、图片文件)。
const experss = require('express');
const path = require('path');
const app = experss();
app.listen(3000, () => {
console.log(`web服务器工作在3000端口`);
});
//使用内置中间件express.static()来开放静态资源:
//注意:将某个目录开放之后在访问时不需要带上该目录名称
// app.use('/img', experss.static(path.join(__dirname, 'img')));
// app.use('/css', experss.static(path.join(__dirname, 'css')));
// app.use('/js', experss.static(path.join(__dirname, 'js')));
app.use(experss.static(path.join(__dirname, 'public')));
//显示登录界面:
app.get('/login', (req, res) => {
res.sendFile(path.join(__dirname, 'login.html'));
});
// //显示图片:
// app.get('/img/good_banner3.png', (req, res) => {
// res.sendFile(path.join(__dirname, 'img/good_banner3.png'));
// });
中文文档参考地址:Express 4.x - API Reference - Express 中文文档 | Express 中文网
app.use(express.urlencoded({extended:false}))
在某.http文件中写入类似于下面格式的内容用来模拟post方式发送键值对格式的参数:
@urls= http://localhost:5000
POST {{urls}}/mytest HTTP/1.1
###
POST {{urls}}/dologin HTTP/1.1
Content-Type:application/x-www-form-urlencoded
uname=李四&age=20&tel=110
然后在某个路由中使用req.body来接收post方式发送的参数:
const experss = require('express');
const path = require('path');
const app = experss();
app.listen(5000, () => {
console.log(`web服务器工作在5000端口`);
});
//使用内置中间件express.static()来开放静态资源:
//注意:将某个目录开放之后在访问时不需要带上该目录名称
// app.use('/img', experss.static(path.join(__dirname, 'img')));
// app.use('/css', experss.static(path.join(__dirname, 'css')));
// app.use('/js', experss.static(path.join(__dirname, 'js')));
app.use(experss.static(path.join(__dirname, 'public')));
//使用内置中间件express.urlencoded()接收post方式的键值对格式发送的参数:
app.use(experss.urlencoded({ extended: false }));
app.post('/dologin', (req, res) => {
console.log(req.body, 111);
let { uname, age, tel } = req.body;
res.send(`处理登录 ${uname} ${age} ${tel}`);
});
app.use(express.json())
中文文档参考地址:Express 4.x - API Reference - Express 中文文档 | Express 中文网
在某.http文件中写入类似于下面格式的内容用来模拟post方式发送json格式的参数:
@urls= http://localhost:5000
POST {{urls}}/mytest HTTP/1.1
###
POST {{urls}}/myjson HTTP/1.1
Content-Type: application/json
{"usr":"lisi","email":"[email protected]","y":100}
###
然后在某个路由中使用req.body来接收post方式发送的参数:
const experss = require('express');
const path = require('path');
const app = experss();
app.listen(5000, () => {
console.log(`web服务器工作在5000端口`);
});
//使用内置中间件express.static()来开放静态资源:
//注意:将某个目录开放之后在访问时不需要带上该目录名称
// app.use('/img', experss.static(path.join(__dirname, 'img')));
// app.use('/css', experss.static(path.join(__dirname, 'css')));
// app.use('/js', experss.static(path.join(__dirname, 'js')));
app.use(experss.static(path.join(__dirname, 'public')));
//使用内置中间件express.urlencoded()接收post方式的键值对格式发送的参数:
app.use(experss.urlencoded({ extended: false }));
//使用内置中间件express.json()接收post方式的json格式发送的参数:
app.use(experss.json());
app.post('/myjson', (req, res) => {
console.log(req.body, 9999);
res.send('post参数:');
});
serve-favicon
svg-captcha
npm install svg-captcha
svgCaptcha.create(options)`
var svgCaptcha = require('svg-captcha');
app.get('/captcha', function (req, res) {
var captcha = svgCaptcha.create();
req.session.captcha = 验证码文本;
res.type('svg');
res.status(200).send(captcha.data);
});
如果没有传递任何选项,您将获得一个由四个字符组成的随机字符串和相应的 svg。
size
: 4 // 随机字符串的大小
ignoreChars
: '0o1i' // 过滤掉一些像 0o1i 这样的字符
noise
: 1 // 噪声线数
color
: true // 字符将具有不同的颜色而不是灰色,如果设置了背景选项则为真
background
: '#cc9966' // svg 图像的背景颜色
此函数返回一个具有以下属性的对象:
data
: string // svg 路径数据
text
: string // 验证码文本
svgCaptcha.createMathExpr(options)
与创建 api 类似,您拥有上述选项以及 3 个附加选项:
mathMin
: 1 // 数学表达式的最小值
mathMax
: 9 // 数学表达式的最大值
mathOperator
: + // 要使用的运算符, +
, -
or +-
(for random +
or -
)
此函数返回一个具有以下属性的对象:
data
: string // 数学表达式的 svg
text
: string // 数学表达式的答案
svgCaptcha.loadFont(url)
加载您自己的字体并覆盖默认字体。
url
: string // 字体路径 这个api是opentype.js的loadFont api的包装器。 您可能需要围绕各种选项进行试验,以使您自己的字体可访问。 见下面的api。
svgCaptcha.options
获得对全局设置对象的访问权。它用于 create 和 createMathExpr api 作为默认选项。
除了大小、噪声、颜色和背景之外,您还可以设置以下属性:
width
: number // 验证码的宽度
height
: number // 验证码高度
fontSize
: number // 验证码文本大小
charPreset
:string // 随机字符预设
svgCaptcha.randomText([size|options])
返回一个随机字符串。
svgCaptcha(text, options)
根据提供的文本返回 svg 验证码。
在 1.1.0 之前的版本中,您必须调用这两个函数, 现在您可以调用 create() 来保存一些按键;)。