express的介绍
express官网:www.expressjs.com.cn/
Express是一个基于node.js的极简、灵活的web应用开发框架。
Express可以快速搭建一个完整功能的网站。
Express的作用于node.js中的内置的http模块类似,都是用来创建web服务的。但是http模块使用起来比较繁琐。开发效率低,Express是基于http模块封装出来的,能够极大的提高开发效率。
http与Express的关系:JavaScript原生操作DOM 与 JQuery的关系。
安装Express
在项目的根目录下,输入【npm init】初始化。
运行
npm i express
创建服务器
const express = require("express")
//创建服务
let app = express();
app.get("/",(req,res)=>{
res.send("Hello,world!")
})
app.listen(3000,()=>{console.log("服务器已启动");})
路由
什么是路由
路由就是网址,web服务器会根据用户输入的不同路径和请求方式,响应不同的页面。
基本格式
路由的组成:请求地址+请求方式。
http常见的请求方式:post(添加),get(获取)put(更新)delete(删除)
app.method(path,handler)
//method:请求方式
//path:请求路径
//handler:请求的处理函数。
匹配规则:每当一个请求到达服务器后,需要经过路由的匹配。匹配请求地址和请求方式,匹配成功后,才会调用对应的处理函数。
模块化路由
为了方便对路由进行管理,Express不建议我们将所有的路由都罗列在一个文件中。
我们可以将路由分类,将同一类的路由抽离为一个模块。
- 创建路由模块对应的js文件
- 调用express.Rotuer()方法创建路由对象。
- 在路由对象上挂载具体的路由。
- 使用module.exprots导出路由对象
- 在app.js中使用app.use方法来注册路由模块。
order.js文件如下
const express = require("express");
/**
* 订单路由模块
*/
// 2.调用express.Rotuer()方法创建路由对象。
const order = express.Router();
//3.在路由对象上挂载具体的路由。
order.post("/order/add",(req,res)=> res.send("新增了一个订单"));
order.post("/order/edit",(req,res)=> res.send("修改了订单信息"));
order.post("/order/del",(req,res)=> res.send("删除了一个订单"));
order.get("/order/list",(req,res)=> res.send("查询所有的订单信息"));
//4.使用module.exprots导出路由对象
module.exports = order;
app.js文件如下
//引入express框架
const express = require('express');
//创建网站服务器
const app = express();
const order = require('./order');
app.use(order);
//app.use('/home',home);
app.listen(3000, function () {
console.log('Example app listening on port 3000!')
})
获取get参数
Express框架中使用req.query即可获取GET参数,框架内部会将GET参数转换为对象并返回。
app.get("/login",function(req,res){
console.log(req.query);
res.send("登录");
});
获取post参数
// 如果设置为false,那么对URL-encoded的数据的解析采用querystring
// 默认值为true,但是不赞成使用默认值。
app.use(express.urlencoded({ extended: false }));
// 接收请求
app.post('/add', (req, res) => {
// 接收请求参数
console.log(req.body);
})
动态参数
通过req.params对象,可以访问到url中,通过:匹配到的动态参数。
const express = require("express");
var app = express();
app.get("/",function(req,res){
res.send(`<h1>oh no</h1>`);
});
app.get("/login/:aid",function(req,res){
res.send(req.params);
});
app.listen(3000);
中间件
中间件介绍
中间件就是处理HTTP请求的函数,做接收到请求和发送响应中间的一系列操作。
注册中间件
通过使用app.use()和app.METHOD()注册中间件,其中METHOD是请求方法的小写(如GET、PUT或POST)
app.use 匹配所有的请求方式,接收所有的请求。
app.use((req, res, next) => {
console.log(req.url);
//注意:在当前中间件处理完毕后,必须调用next()函数
//表示调用下一个中间件或路由。
next();
});
中间件的作用
多个中间件之间,共享同一份req和res,基于这样的特性,我们可以在上游的中间件中,为req或res对象添加自定义的属性或方法,供下游中间件或路由使用。
案例:获取请求到达服务器的时间。
如果按照之前的写法,我们需要在每个路由函数中进行处理。
app.use((req, res, next) => {
console.log(new Date());
next();
});
案例:请求不到的路由,响应404
app.get('/login',(req,res)=>{
res.render('login',{login:'123'})
})
app.post('/dologin',(req,res)=>{
res.send(req.body);
})
// 错误处理中间件 //类似于拦截器
app.use((req,res)=>{
res.status(404).send('不存在');
});
定义多个全局中间件
可以使用app.use()连续定义多个全局中间件,客户端请求到达服务器之后,会按照中间件定义的先后顺序依次进行调用
注意事项
- 一定要在路由之前注册中间件。
- 客户端发送来的请求,可以连续调用多个中间件进行处理。
- 执行完中间件的代码之后,不要忘记调用next()函数。
- 为了防止代码逻辑混乱,调用next()函数后不要再写额外的代码。
案例:错误处理中间件
顾名思义,它是指当程序出现错误时所执行的操作。比如,匹配不到路由,文件读取失败等等。错误处理中间件和其他中间件基本一样,只不过其需要开发者提供4个自变量参数。
错误中间件放到最后,才可以接受到错误。通过接受err参数判断是否触发该中间件
const express = require('express')
const fs = require('fs')
const path = require('path')
const app = express()
app.get('/a',(req, res, next) => {
res.end('hello')
})
app.get('/',(req, res, next) => {
try {
const data = JSON.parse("{name:}");
res.send(data);
}catch (e){
next(e);
}
})
/*
app.get('/',(req, res, next) => {
fs.readFile(path.join(__dirname,"ccc.log"),(err,data)=>{
if(err){
next(err);
}
});
})
*/
/*
统一的错误处理日志中间件
*/
app.use((err,req, res, next) => {
const err_log = `
+---------------+-------------------------+
错误名称:${err.name},\n
错误信息:${err.message},\n
错误时间:${new Date()},\n
错误堆栈:${err.stack},\n
+---------------+-------------------------+
`
fs.appendFile(path.join(__dirname,"error.log"),err_log,()=>{
res.writeHead(500,{'Content-Type':'text/html;charset=utf-8'});
res.end(`500 服务器内部错误`);
});
})
app.listen(3000,()=>{
console.log('running```')
})
静态资源访问
const express = require('express')
const path = require('path')
const app = express()
// path.join(__dirname, 'public') 表示工程路径后面追加 public
app.use(express.static(path.join(__dirname, 'public')))
app.listen(3000, () => {
console.log(`App listening at port 8080`)
})
【注意】Express在指定的静态目录中查找文件,并对外提供资源的访问路径。因此,存放文件的目录名不会出现在URL中。
多个静态资源目录
如果要托管多个静态资源目录,多次调用express.static方法即可,但是需要注意的一点是:express会根据目录的添加顺序查找所需的文件。
ejs模板引擎
模板引擎是什么
模版引擎能帮我们我们动态的生成 HTML 内容。且可以实现HTML代码与js代码的分离。
使用方法
下载安装
cnpm install ejs --save
设置
//设置默认使用的模板引擎
app.set("view engine", "ejs");
app.get("/", (req,res)=>{
res.render("index"); //不需要写res.render("./views/index.ejs");
})
新建ejs文件
新建views文件夹存放模板文件。在views文件夹下新建ejs文件,注意,扩展名必须是ejs,不是html。
渲染数据
app.get("/",(req,res)=>{
//呈递页面
res.render("index",{
"name" : "zhangsan"
});
});
ejs 的语法
插值语句 <%= value %>
<p><%= title %></p>
流程控制语句 if语句 <% js代码 %>
- if语句
// js 的if 语句格式
<% if(条件) { %>
// 处理的逻辑 渲染的HTML结构
<% } %>
- if-else语句
// js 的if 语句格式
<% if(条件) { %>
// 处理的逻辑 渲染的HTML结构
<% }else { %>
// 处理的逻辑 渲染的HTML结构
<% } %>
- if-else的嵌套
// js 的if 语句格式
<% if(条件) { %>
// 处理的逻辑 渲染的HTML结构
<% }else if(){ %>
// 处理的逻辑 渲染的HTML结构
<% }else if(){ %>
// .....
<% else {%>
// ...
<% }%>
流程控制语句 for循环语句 <% js代码 %>
- for循环
<%for(let i = 0; i < arr.length; i++) {%>
// 处理的逻辑 渲染的HTML结构
<% } %>
- forEach 循环
<% arr.forEach(function(item, index) { %>
// 处理的逻辑 渲染的HTML结构
<% }) %>