总结
初始化
- 一、创建一个空的目录、项目包初始化(
npm init -y / yarn init -y
)
下载express包:npm i express / yarn add express
这个包下载的时候一定是一个生产环境依赖
创建一个服务文件(server.js)
-
二、创建一个服务文件(server.js)
-
2.1 导包(引入模块)
const express = require('express');
-
2.2 创建服务对象
const app = express();
-
2.3 建立路由规则
app.get('/路由名称',(request,response)=>{})
get请求app.post('/路由名称',(request,response)=>{})
post请求app.put('/路由名称',(request,response)=>{})
put 修改请求app.patch('/路由名称',(request,response)=>{})
patch修改请求app.delete('/路由名称',(request,response)=>{})
delete 删除请求app.all('/路由名称',(request,response)=>{})
all代表所有的请求方式 都能进入此路径app.all('*',(request,response)=>{})
– 这条路由规则放在最后
*表示所有的路径的匹配(全局路径的通配符)
注意事项:*表示的所有路径,包含前面所规定的固定的名称的路径,如果放在最前面那么用户输入什么路由规则都满足,那么我们一般放在路由规则的最后 -
2.4 建立监听端口
app.listen(端口号,()=>{
console.log(‘xx端口号正常运行中…’)
})
-
请求报文对象 request
-
三、请求报文对象 request
-
请求行:
请求类型:request.method
请求url:request.url
http协议版本:request.httpVersion
-
请求头:
request.headers
返回的一个对象let {host,connection} = request.headers;
get虽然没有请求体传递数据,但是可以通过请求字符串的方式传递
-
请求字符串:?参数名=参数值&参数名=参数值…
请求字符串的出现情况:
- 1)可以直接在
url地址的后面手动输入
:http://localhost/user?a=1&b=2 - 2)
表单get提交方式
:需要给要提交的表单元素添加一个name属性 name属性名就是query对象键名 属性值就是用户填写值 - 3)
超链接
< a href=“http://localhost/路由名称?参数名=参数值&参数名=参数值”>xxx< /a >
- 1)可以直接在
获取请求字符串:
request.query
返回的也是一个对象 {a:1,b:2}路由占位符:出现一定是url中的某一些位置的值是不确定的,则这个不确定的位置就可以使用占位符来规定
占位符就是一个单词的符号,可以自定义
http://www.jd.com/10-149.html
http://www.jd.com/10-120.html -
例如:http://www.jd.com/10-:id/20-:id1.html
http://www.jd.com/10-100/20-200.html
获取占位符中的内容:request.params
返回的也是一个对象 {id:100,id1:200}
响应报文对象 response
- 四、响应报文对象 response
-
响应行:
response.statusCode = 状态码
;
response.statusMessage = 值
;
response.status(状态码)
-
响应头:
response.setHeader('头名','头值')
;例如:
response.setHeader('Content-Type','text/html;charset=utf-8');
response.setHeader('Access-Control-Allow-Origin','*');
设置跨域Content-Type的设置
('Content-Type', 'application/x-www-form-urlencoded')
设置post请求的数据格式
('Content-Type', 'text/html;charset=utf-8')
数据可以是纯文本也可以是html 类似于innerHTML
('Content-Type', 'text/plain;charset=UTF-8')
数据是纯文本格式 类似于innerText
('Content-Type', 'application/json; charset=utf-8')
JSON格式的数据 -
响应体:
response.end()
以下方法是express扩展的
response.send("xxxx");
返回字符串
response.json({name:"姓名"});
返回对象end和send的区别
send是setHeader方法+end方法的姐合,将响应头的响应体的数据类型以及字符集和end方法结合
response.setHeader(‘Content-Type’,‘text/html;charset=utf-8’);response.download(__dirname+'/文件路径')
响应下载文件
response.sendFile(__dirname+'/文件路径')
将文件的内容进行输出[redirect后期项目会用到] 路由的重定向
response.redirect('/路由名称')
直接定向到某一个路由规则
response.redirect('/路由名称?参数名=参值...')
定向到某一个路由规则并且传递请求字符串参数
response.redirect('外网网址')
定向到外网网址注意事项:download、sendFile、redirect都可以直接使用,不和end连用,
否则不使用这几种方式那么必须代码的最后要设置响应体(end/send)
// 1引入express模块
const express = require('express');
// 2创建服务对象
const app = express();
// 3设置路由规则
// get 请求
app.get('/login',(request,response)=>{//request 请求报文对象 response响应报文对象
// 请求报文 行 头 空行 体
const {method , url , httpVersion, headers:{host , connection}} = request;
// method 请求类型 url 请求地址 headers 请求头 host 主机 httpVersion 版本号
//获取请求字符串 http://localhost/user?a=1&b=2
request.query //{a:1,b:2}
// end和send的区别
//send是setHeader方法+end方法的姐合,将响应头的响应体的数据类型以及字符集和end方法结合
//response.setHeader('Content-Type','text/html;charset=utf-8');
response.send('登录成功');
})
// post请求
app.post('/register/:id/:age',(request,response)=>{
//获取路由占位符中的内容 http://localhost/register/15/18?a=1&b=2
request.params ;//{id:15,age:18}
response.send('注册成功');
})
// all代表所有的请求方式 都能进入此路径
app.all('/user',(request,response)=>{
// 响应状态码
response.statusCode;
// 响应状态字符串
response.statusMessage;
// 设置响应头
response.setHeader('aa','11');//自定义响应头
// 响应下载文件
response.download(__dirname+'index.txt');
// 将文件的内容进行输出
response.sendFile(__dirname+'index.txt');
// 路由的重定向
//直接定向到某一个路由规则
response.redirect('./uesr')
//定向到某一个路由规则并且传递请求字符串参数
response.redirect('/denglu?name=admin&age=23&pass=123');
//定向到外网网址
//注意事项:外网网址一定要写协议!!!
response.redirect('http://www.baidu.com');
// 设置响应状态码
response.status(400)
//注意事项:download、sendFile、redirect都可以直接使用,不和end连用,
//否则不使用这几种方式那么必须代码的最后要设置响应体(end/send)
})
//*表示所有的路径的匹配(全局路径的通配符)
//注意事项:*表示的所有路径,包含前面所规定的固定的名称的路径,如果放在最前面那么用户输入什么路由规则都满足,那么我们一般放在路由规则的最后
app.post("*",(request,response)=>{
response.end('404 not Found');
})
//4设置监听端口
app.listen(8080,()=>{
console.log('8080端口服务启动成功');
})
中间件
- 五、中间件
- 全局中间件
- 定义单个全局中间件
let recordMiddleware = function(request,response,next){
//实现功能代码
//.....
//执行 next 函数(当如果希望执行完中间件函数之后,仍然继续执行路由中的回调函数,必须调用 next)
next();
}
app.use(recordMiddleware);
简写形式
app.use(function(request,response,next){
next();
});
-
- 定义多个全局中间
方式一
app.use(function (request, response, next) {
console.log('定义第一个中间件');
next();
})
app.use(function (request, response, next) {
console.log('定义第二个中间件');
next();
})
方式二
//或者
/*let loginMiddleWare = (request, response, next) => {
console.log('我是全局中间件 1');
next();
}
let login1MiddleWare = (request, response, next) => {
console.log('我是全局中间件 2');
next();
}
app.use(login1MiddleWare, loginMiddleWare);*/
-
路由中间件
- 定义单个路由中间件
app.get('/路由规则',
中间件函数,(request,response)=>{});
- 定义单个路由中间件
定义中间件函数 m1
const m1 = function(request,response,next){
console.log('这是中间件函数');
}
创建路由规则
app.get('/',m1,(request,response)=>{
response.end('Home Page');
});
-
- 定义多个路由中间件
方式一
app.get('/路由规则',`中间件函数1`,`中间件函数2`,(request,response)=>{});
或者方式二
app.get('/路由规则',[中间件函数1,中间件函数2..],(request,response)=>{});
- 静态资源中间件的使用
app.use(express.static('./public'));
app.use('/upload',express.static(path.join(__dirname,'./upload')))
代表的意思是在/upload路由中访问项目中./upload文件夹下的静态资源文件,前端通过访问/upload + 文件名来获取文件
获取 post 请求的请求体数据 body-parser
- 六、获取 post 请求的请求体数据 body-parser
1、安装
npm i body-parser
2、导入 body-parser 包
const bodyParser = require('body-parser');
3、设置使用 body-parser 中间件
//extended:true,那么你可以解析嵌套对象,或者通常是任何类型
//extended:false,则只能解析字符串或数组
app.use(bodyParser.urlencoded({extended:false}));
4、使用 request.body
来获取请求体数据
app.post('/login',(request,response)=>{
//获取请求体数据
//console.log(request.body);
//用户名
console.log(request.body.username); //admin
//密码
console.log(request.body.userpass); //123456
response.send('获取请求体数据');
});
Router 路由器
- 七、Router 路由器
子文件
//1、导入包
const express = require('express');
//2、创建子路由对象
const userRoutes = express.Router();
//3、通过子路由对象来规定路由规则
userRoutes.get('/user', (request, response) => {
response.send('用户功能');
})
//4、暴露模块
module.exports = userRoutes;
主文件
//1.引入 express
const express = require('express');
//2.引入子路由文件
const homeRouter = require('./routes/homeRouter');
const userRouter = require('./routes/userRouter');
//3.创建 app 对象
const app = express();
//4.设置和使用中间件 配置路由的方式
//引入单个路由 可以设置第一个参数来配置路由 形成第一个参数和子路由的拼接 /user/userCenter
app.use('/user',homeRouter);
app.use(homeRouter);//引入单个路由
app.use(homeRouter,userRouter);//引入多个路由
//5.监听端口
app.listen(80,()=>{
console.log('80 端口启动....');
})
EJS
- 八、EJS
- 1、EJS 单独使用
下载安装 EJSnpm i ejs --save
//1.引入ejs
const ejs = require('ejs');
//2.定义数据
let person = ['张三','李四','王二麻子'];
//3.ejs解析模板返回结构
//<%= %> 是ejs解析内容的标记,作用是输出当前表达式的执行结构
//ejs.render('<%= 输出的内容 %>',{键名:键值}) 返回的是一个字符串内容
//render方法的第二个参数对象中的键名就是模板文件中的变量名
//对象中的键值就是变量文件中的变量名对应的实际值
let html = ejs.render(‘<%= person.join(",") %>’, {person:person});
//4.输出结果
console.log(html);
- 2、EJS 在 express 中的使用
配置模板引擎app.set('view engine','ejs');
配置模板的存放目录app.set("views","./views")
const express = require('express');
const app = express();
app.set('view engine','ejs');
//注意:创建的模板文件后缀需要是 ejs,且创建的位置需要在 views 文件夹里面
app.set('views',\_\_dirname + '/views'); //目录可以自定义
app.get('/',(request,response)=>{
let zym = '细节决定成败';
let stars = ['SHE','羽泉','beyond'];
response.render('home',{zym,stars}); //第一个参数为模板文件名
});
后台获取form上传的文件
- 安装
npm i formidable
- 前端通过
new FormData(formDOM元素)
获取form表单中的数据
//获取表单数据
let myformdata = new FormData(document.advForm);
try {
//发送ajax请求
let result = await axios.post('/addAdv', myformdata);
toastr.success(result.message);
console.log(result)//获取后端返回的数据
} catch (e) {
toastr.error(e.msg);
}
- 后端通过formidable获取前端传输的数据
//3、建立路由规则
//导入formidable
const formidable = require("formidable");
AdvRoutes.post("/addAdv", (request, response) => {
// 创建表单对象,接收前端提交的数据
const form = new formidable.IncomingForm({
uploadDir: path.resolve(__dirname, "../uploads"), //设置文件上传的路径目录
keepExtensions: true, //设置是否保留扩展名
encoding: "utf-8", //设置提交的数据的编码格式
maxFieldsSize: 2 * 1024 * 1024, //设置文件上传的最大限制
});
form.parse(request, async (err, fields, files) => {
// files 图片上传相关的字段值
// console.log('非图片以外的所有的字段值:', fields)
// console.log('图片的新的文件名:', files.advPic.newFilename)
//完成数据的添加
let result = await advModel.create({
...fields,
advImg: files.advPic.newFilename,
createTime: nowTime(),
});
if (result) {
response.json({
code: 10000,
message: "添加广告数据成功",
});
} else {
response.json({
code: 10001,
message: "添加广告数据失败",
});
}
});
});
express框架
一、什么是Express
Express是一个基于Node.js平台的极简、灵活的web应用开发框架,说白了,就是一个被封装好的npm的包,提供
了很多功能,封装了很多api,让我们在做web开发的时候,变得非常的便利,能够提高我们对于web开发应用的效
率,有了它,咱们在构建服务的时候就会变的很方便,尤其在请求响应的时候。
简单来说,Express就是运行在node中的用来搭建服务器
的模块。
而且也是基于node.js中的http模块基础之上构建了自己的一些应用和语法。
官方网址:https://www.expressjs.com.cn/
二、Express的使用
2.1 Express的下载
npm i express --save # 安装express并添加到依赖项
注意:安装的文件夹名称、package.json文件中的name;都不能与express重复;且需要先初始化init
2.2 Express的使用
-
引入express框架
const express = require('express'); # 返回值一个函数
-
创建服务对象
const app = express(); # 函数调用
-
创建路由规则
【根据用户的请求,来执行不同的回调】
例如:
app.get('/',(request,response)=>{ # 当请求方式为get,且请求路径为/,则执行该回调函数
//响应的内容如果为中文,容易乱码,可以设置响应头
response.setHeader('Content-type','text/html;charset=utf-8');
response.end('home首页')
})
app.get('/admin',(request,response)=>{ # 当请求方式为get,且请求路径为/admin,则执行该回调函数
response.end('admin管理页')
})
- 监听端口启动服务
app.listen(80,()=>{
console.log('服务已经启动80端口监听中');
})
三、Express的路由
3.1 什么是路由
路由是指如何定义应用的端点(URIs)以及如何响应客户端的请求,是由一个 URI、HTTP 请求(GET、POST等)
和若干个句柄组成的。
3.2 路由的定义
我们可以将路由定义为三个部分:
第一部分:HTTP请求的方法(get或post)
第二部分:URI路径
第三部分:回调函数
3.3 路由的实现
Express中提供了一系列函数,可以让我们很方便的实现路由。
app.<method>(path,callback)
- method指的是HTTP请求方法,例如:app.get()、app.post()、app.all()
- path指要通过回调函数来处理的URL地址,例如:/、/admin、/login、*
- callback参数是应该处理该请求并把响应发回客户端的请求处理程序
例如:get请求
//1.引入express
const express = require('express');
//2.创建express对象
const app = express();
//3.创建路由规则
app.get('/',(request,response)=>{
response.setHeader('Content-type','text/html;charset=utf-8');
response.end('首页');
})
//4.监听端口并启动服务
app.listen(80,()=>{
console.log('服务已经启动,80端口正在运行中');
})
例如:post请求
<!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>
<form action="http://127.0.0.1/login" method="post">
用户名:<input type="text" name="username"/>
<button>登录</button>
</form>
</body>
</html>
//1.引入express框架
const express = require('express');
//2.创建express对象
const app = express();
//3.建立路由规则
app.post('/login',(request,response)=>{
response.end('login');
});
//4.监听端口并启动服务
app.listen(80,()=>{
console.log('80端口启动....');
})
例如:all请求
表示所有的请求方式均可。
app.all('/admin',(request,response)=>{
response.end('admin page');
})
*:表示全局匹配路径的通配符,任何的请求路径均可。
app.all('*',(request,response)=>{
response.statusCode = 404;
response.end('<h1>404 Not Found</h1>');
})
3.4 请求参数的获取
利用express框架api来获取请求报文中的内容参数,express框架中获取请求数据的方式和原生的http模块是兼容的。
//引入express框架
const express = require('express');
//创建服务对象
const app = express();
//规则
app.get('/req',(request,response)=>{
//请求方式
console.log(request.method);
//请求路径
console.log(request.url);
//http版本
console.log(request.httpVersion);
//请求头
console.log(request.headers);
//express提供的API
//查询字符串
console.log(request.query); // {a:1,b:2}
//响应
response.end('request');
});
app.listen(80,()=>{
console.log('80端口启动....');
})
3.5 路由参数的设置以及获取
app.get('/:id.html ',(request,response)=>{
//获取路由中的请求参数
console.log(request.params.占位符名称)
});
四、express响应的设置
express框架中response使用的方式和原生的http模块是兼容的。
//引入express框架
const express = require('express');
//创建服务对象
const app = express();
//路由规则
app.get('/res',(request,response)=>{
//响应状态码
response.statusCode = 401;
//响应状态字符串
response.statusMessage = 'Error';
//设置响应头
response.setHeader('a','101');
//设置响应体
response.end('body');
//express中独有的API响应
response.send();
/*
* 区分end()和send()
* 相同点:都是可以设置响应体
* 不同点:send()除了设置响应体之外,还可以额外增加一个响应头
* 相当于response.setHeader();
* 如果响应的内容为中文的话,那么使用send则不会是乱码
*/
//下载文件的响应
response.download('文件路径'); //适合于软件、音乐、视频等文件的下载
//其核心就是在response Headers中有一个Content-Disposition:attachment;filename="xx"
//响应文件的内容
response.sendFile(__dirname + '/文件的路径'); //注意这个路径必须是绝对路径
//重定向
response.redirect('login');
//其核心就是在response Headers中有一个Location
//响应状态码的设置
response.status(400);
//响应状态码的设置一定要伴随着响应体
response.send('body');
});
//监听端口
app.listen(80,()=>{
console.log('80端口启动....');
})
五、中间件
5.1 什么是中间件
Express是一个自身功能极简,完全是由路由和中间件构成一个web开发框架。
从本质上来说,一个Express应用就是在调用各种中间件。
中间件(Middleware)是一个函数
,它可以访问请求对象(request)
,响应对象
(response)
和web应用中处于请求-响应循环流程中的中间件,一般被命名为next
的变量。
例如:我们可以举一个生活中的例子来更好的理解它:
在处理污水的时候,一般都要经过三个处理环节,从而保证处理过后的废水,达到排放标准。
处理污水的这三个中间处理环节,就可以叫做中间件。
当一个请求到达 Express 的服务器之后,可以连续调用多个中间件,从而对这次请求进行预处理。
例如现在我们定义一种需求:我们需要获取请求到达服务器的时间
如果我们不使用中间件的话,我们就需要在每一个路由中都进行单个的获取,这无疑非常的麻烦。
const express = require('express');
const app = express();
app.get('/',(request,response)=>{
const time = Date.now();
response.end('Home Page.');
});
app.get('/user',(request,response)=>{
const time = Date.now();
response.end('User Page.');
});
app.listen(80,()=>{
console.log('http://127.0.0.1');
})
5.2 中间件的类型
- 全局中间件
- 路由中间件
5.3 定义全局中间件
每一次路由的请求到达服务端之后都要执行中间件 ,无论是否存在该路由规则,中间件函数都会执行。
let recordMiddleware = function(request,response,next){
//实现功能代码
//.....
//执行next函数(当如果希望执行完中间件函数之后,仍然继续执行路由中的回调函数,必须调用next)
next();
}
调用了next函数代表这个中间件处理完毕了,要交给下一个中间件或者路由去处理了。
一般情况下程序中必须要做的事情都会在全局中间件中设置。
app.use(recordMiddleware);
5.3.1 定义全局中间件的简化形式
app.use(function (request, response, next) {
console.log('定义第一个中间件');
next();
})
上面的案例就可以修改成
const express = require('express');
const app = express();
//定义全局中间件的简化形式
app.use((request,response,next)=>{
//获取请求到达服务器的时间
const time = Date.now();
//然后再request请求对象身上挂载自定义属性,从而将时间共享到后面所有的路由
request.startTime = time;
next();
});
app.get('/',(request,response)=>{
response.end('Home Page.' + request.startTime);
});
app.get('/user',(request,response)=>{
response.end('User Page.' + request.startTime);
});
app.listen(80,()=>{
console.log('http://127.0.0.1');
})
5.3.2 定义多个全局中间件
使用 app.use() 定义多个全局中间件,客户端请求到达服务器之后,会按照中间件定义的先后顺序依次进行调用。
//1、引入express
const express = require('express');
//2、 创建服务对象
const app = express();
//5、创建中间件(全局中间件、路由中间件)
//5.1 定义全局中间件
app.use(function (request, response, next) {
console.log('定义第一个中间件');
next();
})
app.use(function (request, response, next) {
console.log('定义第二个中间件');
next();
})
//或者
/*let loginMiddleWare = (request, response, next) => {
console.log('我是全局中间件1');
next();
}
let login1MiddleWare = (request, response, next) => {
console.log('我是全局中间件2');
next();
}
app.use(login1MiddleWare, loginMiddleWare);*/
//3、创建路由规则
app.get('/login', (request, response) => {
//判断
response.end('login');
});
//4、设置端口
app.listen(80, () => {
console.log('80端口正在运行中');
})
5.4 定义路由中间件
当想要某一些路由在请求的时候,需要中间件函数的支持,则就不需要设置全局中间件,而需要在路由规则中设置
不使用 app.use() 定义的中间件,也叫做局部生效的中间件。
app.get('/路由规则',`中间件函数`,(request,response)=>{
});
//1、引入express
const express = require('express');
//2、 创建服务对象
const app = express();
//3、定义中间件函数 m1
const m1 = function(request,response,next){
console.log('这是中间件函数');
}
//4、创建路由规则
app.get('/',m1,(request,response)=>{
response.end('Home Page');
});
//5、设置监听端口
app.listen(80,()=>{
console.log('80端口正在启动中...');
})
如果需要多个中间件函数,那么就可以将所需要的中间件函数都列上
app.get('/路由规则',中间件函数1,中间件函数2,(request,response)=>{
});
写成数组的形式也是可以的。
app.get('/路由规则',[中间件函数1,中间件函数2..],(request,response)=>{
});
5.5 获取请求体数据 body-parser
5.5.1 注意事项
-
如果请求方式为GET,咱们可以使用express中内置api(request.query)/ request.params
- query:接受的是地址栏中的?的请求字符串的数据
- params:接受的是url中的占位符的名称
-
如果请求方式为POST,express中没有内置获取表单post请求体的API,这里咱们需要借助第三方包body-parser
5.5.2 使用方式
第一步:安装
npm i body-parser
第二步:导入body-parser包
const bodyParser = require('body-parser');
第三步:设置使用body-parser中间件
app.use(bodyParser.urlencoded({extended:false}));
第四步:使用request.body来获取请求体数据
切记:表单中元素必须要设置name属性,否则无法获取请求体数据
<body>
<form action="http://127.0.0.1/login" method="post">
<p>用户名:<input type="text" name="username"></p>
<p>密码:<input type="password" name="userpass"></p>
<p><button>登录</button></p>
</form>
</body>
app.post('/login',(request,response)=>{
//获取请求体数据
//console.log(request.body);
//用户名
console.log(request.body.username); //admin
//密码
console.log(request.body.userpass); //123456
response.send('获取请求体数据');
});
获取到的请求体数据:
[Object: null prototype] { username: 'admin', userpass: '123456' }
5.6 静态资源中间件的使用
静态资源:长时间不发生改变的资源,称之为静态资源,例如:css、js、img、font、html。
动态资源:内容经常发生改变的资源,称之为动态资源。
站点托管(静态资源托管static)
1、直接访问服务器地址时,会将static方法托管的文件夹中的index.html返回前端浏览器
2、只托管指定文件夹内的内容
3、用于托管服务器总的前端资源(前端代码)
//引入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(80,()=>{
console.log('80端口启动....');
});
文件路径托管
1、all方法只能写在脚本最后
2、托管服务器根目录中的所有文件
3、访问时需要书写完整文件在服务器根目录中的地址
4、用于托管服务器资源(图片、视频、头像等)
app.all('*',(request,response)=>{
console.log(request.url);// 资源地址url
console.log(__dirname);//根目录路径
response.sendFile(__dirname + request.url) //拼接的形式获得资源绝对路径
})
六、Router路由器
6.1 什么是Router
Router是一个完整的中间件和路由系统,也可以看做是一个小型的app对象。
6.2 为什么要使用Router
目的主要是为了更好的分类来管理我们的route。
6.3 Router的使用
目的:拆分路由代码
第一步:创建单独的路由文件,名称和位置都是自定义
子文件
- 引入express框架
const express = require('express');
- 创建路由对象
const route = express.Router();
- 使用route对象代替app对象进行路由设置
route.get('路由名称',(request,response)=>{
...
})
- 暴露route对象
module.exports = route;
主文件
- 在主文件中引入子模块文件,并设置中间件
//1.引入express
const express = require('express');
//2.引入子路由文件
const homeRouter = require('./routes/homeRouter');
//3.创建app对象
const app = express();
//4.设置和使用中间件
app.use(homeRouter);
//5.监听端口
app.listen(80,()=>{
console.log('80端口启动....');
})
七、EJS模板引擎
9.1 什么是EJS
EJS是一个高效的Javascript的模板引擎。
模板引擎是为了使用户界面和业务数据(内容)分离而产生的。
简单来说,使用EJS模板引擎技能动态渲染数据,其核心就是一个npm的包
官网:https://ejs.bootcss.com/
9.2 EJS的使用步骤
- 下载安装EJS
npm i ejs --save
- 配置模板引擎
app.set('view engine','ejs');
- 配置模板的存放目录
app.set("views","./views")
- 在views目录下创建模板文件,例如:index.ejs
- 使用模板,通过response来渲染模板
//1.引入ejs
const ejs = require('ejs');
//2.定义数据
let person = ['张三','李四','王二麻子'];
//3.ejs解析模板返回结构
//<%= %> 是ejs解析内容的标记,作用是输出当前表达式的执行结构
let html = ejs.render(‘<%= person.join(",") %>’, {person:person});
//4.输出结果
console.log(html);
9.3 EJS的模板语法
- 执行JS代码
<% code %>
- 输出转义的数据到模板上
<%= code %>
- 输出非转义的数据到模板上
<%- code %>
- if判断
<%
if(a==20){
%>
<h3>a的值是20</h3>
<%
}
%>
- for循环
<%
for(var i=0 ; i<3 ; i++){
%>
<h3>a的值是20</h3>
<%
}
%>
例1:循环输出我喜欢的水果
const ejs = require('ejs');
let fruits = ['苹果','香蕉','橘子'];
let str = fs.readFileSync(__dirname + '/html/page.html').toString();
let res = ejs.render(str,{fruits});
console.log(res);
<body>
<ul>
<% for(let i = 0;i<fruits.length;i++) { %>
<li><%= fruits[i] %></%></li>
<% } %>
</ul>
</body>
例2:循环表格数据
/**
搭建 HTTP 服务.
GET /table 响应一个表格 4 行 3 列表格, 并实现隔行换色 (JS)
*/
const data = [
{
id:1,
name: 'gem',
song: '野狼disco'
},
{
id:2,
name: '周杰伦',
song: '不能说的密码'
},
{
id:3,
name:'林俊杰',
song: '不为谁而作的歌'
},
{
id:4,
name: '五月天',
song:'干杯'
},
{
id: 5,
name: '张艺兴',
song: '莲'
},
{
id:6,
name:'刘德华',
song:'冰雨'
},
{
id: 7,
name: '张学友',
song: '情人'
}
];
require('http').createServer((request, response) => {
let body = '';
body += `<!doctype html>
<html>
<head>
<title>歌曲列表</title>
<meta charset="utf-8" />
<style>
table,td{
border-collapse: collapse;
}
td{
padding:20px 10px;
}
</style>
</head>
<body>
<table border="1">
<tr><td>ID</td><td>歌手名称</td><td>歌曲</td></tr>`;
//根据数组的数据, 拼接 tr 标签内容
data.forEach(item => {
body += `<tr><td>${item.id}</td><td>${item.name}</td><td>${item.song}</td></tr>`;
});
body += `</table>
</body>
</html>`;
//响应结果
response.end(body);
}).listen(80);
获取读取页面
//1. 导入 ejs
const ejs = require('ejs');
//2、导入 fs
const fs = require('fs');
//3. 准备数据
const data = [
{
id:1,
name: 'gem',
song: '野狼disco'
},
{
id:2,
name: '周杰伦',
song: '不能说的密码'
},
{
id:3,
name:'林俊杰',
song: '不为谁而作的歌'
},
{
id:4,
name: '五月天',
song:'干杯'
},
{
id: 5,
name: '张艺兴',
song: '莲'
},
{
id:6,
name:'刘德华',
song:'冰雨'
},
{
id: 7,
name: '张学友',
song: '情人'
}
];
let html = fs.readFileSync('./table.html').toString();
//4. 解析
const result = ejs.render(html, {data});
console.log(result);
<head>
<title>歌曲列表</title>
<meta charset="utf-8" />
<style>
table,
td {
border-collapse: collapse;
}
td {
padding: 20px 10px;
}
</style>
</head>
<body>
<table border="1">
<tr>
<td>ID</td>
<td>歌手名称</td>
<td>歌曲</td>
</tr>
<% for(let i=0;i<data.length;i++){ %>
<tr>
<td>
<%= data[i].id %>
</td>
<td>
<%= data[i].name %>
</td>
<td>
<%= data[i].song %>
</td>
</tr>
<% } %>
</table>
</body>
9.4 EJS在express中的使用
const express = require('express');
const app = express();
app.set('view engine','ejs');
//注意:创建的模板文件后缀需要是ejs,且创建的位置需要在views文件夹里面
app.set('views',__dirname + '/views'); //目录可以自定义
app.get('/',(request,response)=>{
let zym = '细节决定成败';
let stars = ['SHE','羽泉','beyond'];
response.render('home',{zym,stars}); //第一个参数为模板文件名
});
座右铭:<span><%= zym %></span>
<ul>
<% for(let i = 0; i<stars.length;i++) { %>
<li><%= stars[i] %></li>
<% } %>
</ul>
案例1:小册列表页的实现
<!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 crossorigin='anonymous' href="https://cdn.bootcss.com/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
<style>
#container .no-margin-top{
margin-top: 0;
}
.item{
clear:both;
height:auto;
overflow: hidden;
margin-bottom: 15px;
}
</style>
</head>
<body>
<div class="container" id="container">
<h2 class="page-header">小册列表</h2>
<!-- 小册列表 -->
<div class="row">
<% for(let i=0;i<xiaoces.data.length;i++){ %>
<div class="item">
<div class="col-xs-2">
<img class="img-responsive" src="<%= xiaoces.data[i].base_info.cover_img %>" alt="">
</div>
<div class="col-xs-10">
<h4 class="no-margin-top"><a href="/book/<%= xiaoces.data[i].base_info.booklet_id %>"><%= xiaoces.data[i].base_info.title %></a></h4>
<p><%= xiaoces.data[i].base_info.summary %></p>
<p class="price">¥<%= xiaoces.data[i].base_info.price / 100 %></p>
</div>
</div>
<% } %>
</div>
</div>
</body>
</html>
const express = require('express');
const ejs = require('ejs');
const xiaoces = require('./data/xiaoce.json');
console.log(xiaoces);
const app = express();
app.set('view engine','ejs');
app.set('views','./view');
app.get('/',(request,response)=>{
response.render('list',{xiaoces});
})
app.listen(80,()=>{
console.log('80端口正在运行中...');
});
案例2:小册详情页的实现
<!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 crossorigin='anonymous' href="https://cdn.bootcss.com/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<!-- 顶部导航 start -->
<nav class="navbar navbar-default">
<div class="container">
<!-- Brand and toggle get grouped for better mobile display -->
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">Brand</a>
</div>
<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav">
<li class="active"><a href="#">Link <span class="sr-only">(current)</span></a></li>
<li><a href="#">Link</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Dropdown <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="#">Action</a></li>
<li><a href="#">Another action</a></li>
<li><a href="#">Something else here</a></li>
<li role="separator" class="divider"></li>
<li><a href="#">Separated link</a></li>
<li role="separator" class="divider"></li>
<li><a href="#">One more separated link</a></li>
</ul>
</li>
</ul>
<form class="navbar-form navbar-left">
<div class="form-group">
<input type="text" class="form-control" placeholder="Search">
</div>
<button type="submit" class="btn btn-default">Submit</button>
</form>
<ul class="nav navbar-nav navbar-right">
<li><a href="#">Link</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Dropdown <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="#">Action</a></li>
<li><a href="#">Another action</a></li>
<li><a href="#">Something else here</a></li>
<li role="separator" class="divider"></li>
<li><a href="#">Separated link</a></li>
</ul>
</li>
</ul>
</div><!-- /.navbar-collapse -->
</div><!-- /.container-fluid -->
</nav>
<!-- 顶部导航 end -->
<!-- 内容部分 start -->
<div class="container">
<div class="col-xs-10 col-xs-offset-1">
<div class="col-xs-3">
<img class="img-responsive" src="<%= book.base_info.cover_img %>" alt="">
</div>
<div class="col-xs-9">
<h4><%= book.base_info.title %></h4>
<p><%= book.base_info.summary %></p>
<p>价格: <%= book.base_info.price / 100 %></p>
<p>销量: <%= book.base_info.buy_count %></p>
</div>
</div>
</div>
<!-- 内容部分 end -->
</body>
</html>
const express = require('express');
const app = express();
app.set('view engine','views');
app.set('views',__dirname + '/views');
app.get('/book/:id',(request,response)=>{
//获取路由参数
const id = request.params.id;
console.log(id);
//根据id参数获取小册的详情内容
let data = xiaoces.data.find(item=>{
return item.booklet_id === id;
});
console.log(result);
//响应结果
response.render('detail',{book:result});
});
app.listen(80,()=>{
console.log('80端口启动....');
})
八、hosts文件修改使用域名访问
hosts文件是本地域名解析的文件,而域名解析就是通过域名来获取与之对应的ip地址
文件地址:【C:\Windows\System32\drivers\etc\hosts】
找到这个文件打开,添加一条域名解析规则,然后就可以通过域名的方式来访问网站了。
127.0.0.1 网站的域名
但是默认情况下,计算机是不允许对该文件进行修改,需要对其设置权限
对hosts文件右键->属性->安全选项卡->编辑->Users->允许其所有权限
但是注意这种访问方式只能在本机使用,因为域名解析的ip地址是127.0.0.1。