一、express
模块介绍
- 官网:https://www.expressjs.com.cn/
- 基于 Node.js 平台,快速、开放、极简的 Web 开发框架
二、express
模块搭建服务器
npm init -y
初始化项目
npm install express
下载包
require()
导入包
- 要使用
express
这个包 - 要下载,导入,使用
- 新建一个项目文件夹shop,在根目录运行指令
- 初始化项目配置文件指令: npm init -y
- 下载包: npm install express
// 1 导入包
const express = require('express');
// 2 创建express的一个实例
const app = express();
// 4 配置路由
// 表示凡是get请求路径是/的,就会调用第二个参数的回调函数
app.get('/',function(req,res){
// req:表示请求对象
// res:表示响应对象
// 给前端的响应
res.end('hello world')
})
// 表示凡事get请求路径是/login的,就会调用第二个参数的回调函数
app.get('/login',function(req,res){
res.end('success')
})
// 3 监听端口
app.listen(8080,function(){
console.log("服务器监听8080端口成功")
})
// 1-3 步骤完成就开启了一个web服务器
// 4 步骤用于处理指定路由的
// 后端路由:一个路由对应一个资源
三、基本路由
- 后端路由:一个路由地址对应一个资源
- 当前端请求一个后端路由的时候,后端会响应一个对应的资源
- 即使路由地址相同,但是请求方式不同也是两个不同的路由
- 由于浏览器测试接口就是在地址栏输入地址,默认是get请求,测试接口不方便
- 我们一般使用postman这类专门的接口测试工具
1.app.get()
匹配get请求
app.get('路由',中间件函数)
- 要求路由精确匹配
- 只匹配get请求
- 如果路由写"*",表示匹配所有路由
2.app.post()
匹配post请求
app.post('路由',中间件函数)
- 要求路由精确匹配
- 只匹配post请求
- 如果路由写"*",表示匹配所有路由
3.app.all()
精确路由
app.all('路由',中间件函数)
- 要求路由精确匹配
- 可以匹配任意请求方式
- 如果路由写"*",表示匹配所有路由
4.app.use()
指定路由打头
app.use('路由',中间件函数)
- 要求指定路由开始
- 可以匹配任意请求方式
- 如果第一个参数路由不写,表示匹配所有路由
四、中间件函数
- app.get(path,中间件函数1[,中间件函数2,…])
- app.post(path,中间件函数1[,中间件函数2,…])
- app.all(path,中间件函数1[,中间件函数2,…])
- app.use([path,]中间件函数1[,中间件函数2,…])
- []里面的参数是可选择的
- 中间件函数有三个参数
- 第一个参数是:req 请求对象
- 第二个参数是:res 响应对象
- 第三个参数是:next 下一个中间件函数
- next调用就会执行下一个匹配的中间件函数
// 1 导入express
const express = require('express');
// 2 创建express实例
const app = express();
// 4 配置路由
// 如果一个请求可以匹配两个路由
// 按照顺序匹配,匹配了一个以后就不继续匹配了
// 如果希望继续匹配
// 要使用到匹配的中间件函数的第三个参数next
app.all('/api',(req,res,next)=>{
console.log('all api 执行了');
// next代表的是下一个中间价函数,调用就会执行下一个匹配的中间价函数
next()
})
app.get('/api',(req,res,next)=>{
// 中间件函数1
console.log('get api 函数1执行了');
next()
},function(req,res){
// 中间件函数2
console.log('get api 函数2执行了')
})
// 执行顺序:
// /api匹配了三个中间件函数,先执行第一个中间件函数
// 如果有next()就继续执行下个中间件函数
// 如果没有next()后面的中间件函数就不执行了
// 3 监听端口
app.listen('8080',()=>{
console.log('服务器开启成功')
})
五、中间件函数参数
1.req
请求对象的相关api
1.1 query
解析查询字符串
1.2 params
动态路由参数
- req的相关api
- req.query: 可以获取get请求的查询字符串,并解析成对象格式
- req.params: 可以获取动态路由的参数,并解析成对象格式
- 动态路由
- 路由中有一部分内容是不确定的可以写成 /:xxx
// 1 导入express
const express = require('express')
// 2 创建express实例
const app = express()
// 4 配置路由
// 请求地址:http://localhost:8080/api
// 请求方式:get
// 查询字符串:req.query
app.get('/api',(req,res)=>{
console.log("有get请求到了,获取到的查询字符串是")
console.log(req.query); // 获取查询字符串,并转化成对象
res.end('有get请求到了,获取查询字符串')
})
// 请求地址:http://localhost:8080/detail/123/lucy
// 请求方式:get
// 动态路由:请求地址中有一部分内容是不确定的,但是有要能获取这个不确定的内容
// 动态路由传入部分: req.params
app.get('/detail/:id/:type',(req,res)=>{
// :id 是不确定的内容
// :type 是不确定的内容
console.log(req.params);// 动态路由传入部分解析成对象:{id:123,type:'lucy'}
res.end('动态路由')
})
// 请求头里面的cookie的获取要依赖第三方中间件
// post请求的请求主体的获取要依赖第三方中间件
// 3 监听端口
app.listen(8080,function(){
console.log('服务器开启成功')
})
2.res
响应对象的相关api
2.1cookie()
设置cookie
2.2end()
返回格式响应体
2.3json()
返回格式响应体
2.4sendFile()
显示文件
2.5 download()
下载文件
- res的相关api
- 通过响应头给浏览器设置cookie
- 语法:res.cookie(key,value,{expires:‘过期时间的时间对象默认是会话时效’,path:‘cookie的有效路径默认是/’})
- 发送响应主体
- 语法:res.end(‘字符串或者buffer格式的响应体’)
- 语法:res.json(‘object,array,string,boolean,number等数据类型的响应体’)
- 语法:res.sendFile(‘把指定的绝对路径的文件显示在浏览器’)
- 语法: res.download(‘把指定的绝对路径的文件让浏览器下载’)
- 当前文件所在的文件夹的绝对路径
- 语法: __dirname
console.log(__dirname)
// 1 导入express
const express = require('express');
const path = require('path')
// 2 创建express实例
const app = express()
// 4 配置路由
app.get('/api',(req,res)=>{
// 前后端都可以设置cookie
// 用后端响应头来设置cookie,语法:res.cookie(key, value [, options])
res.cookie('time','lucy',{
expires:new Date(Date.now()+3600*1000), // 不用减8小时,后端会自动处理
path:'/'
})
// 返回响应主体
// res.end('hello cookie'); // ()里面一般是buffer或者字符串
// res.json({name:'lucy',age:12}); // ()里面可以是对象,数组,数值,...
// __dirname : 当前文件所在的文件夹的绝对路径
// res.download(path.join(__dirname,'package.json'));// ()里面是一个绝对路径,会触发浏览器下载文件
// res.sendFile(path.join(__dirname,'package.json'))// ()里面是一个绝对路径,会把文件直接显示在浏览器中
})
// 3 监听端口
app.listen(8080)
// req.query : 解析好的查询字符串
console.log(req.query)
// req.params: 解析好的动态路由
console.log(req.params)
// res.cookie:设置cookie
req.cookie('key','value',{
domain:'qf.com',
expires:new Date(Date.now() + 900000),
path:'/abc' // 默认"/"
})
// res.status: 设置响应状态码
res.status(406)
// res.end(a Buffer object, a String): 设置响应主体
// res.json(object, array, string, Boolean, number, or null): 设置响应主体
// res.sendFile: 设置浏览器显示文件
// 文件路径要是绝对路径
res.sendFile(path.resolve(__dirname,'index.html'))
// res.download: 设置前端下载指定文件
// 文件路径要是绝对路径
res.download(path.resolve(__dirname,'index.html'))
// res.jsonp: 设置响应主体
// res.redirect([status,] path):重定向
// res.send('a Buffer object, a String, an object, Boolean, or an Array'): 设置响应主体
3.next
下一个中间件函数
- next调用就会执行下一个匹配的中间件函数
六、app.use()
1.err
错误处理
- 一般写在所有的路由配置的最末尾
- 作用:处理前面的中间件中出现的错误,以免服务器瘫痪
- 语法:app.use((err,req,res,next)=>{})
- 语法:四个参数缺一不可,缺了一个就不是错误处理中间件
// 1 引入express
const express = require('express');
// 2 创建express实例
const app = express()
// 4 配置路由
// 请求地址: http://localhost:8080/api
// 请求方式: get
app.get('/api',(req,res)=>{
console.log("http://localhost:8080/api get");
console.log(a); // 这里有语法错误,a is not defined
// 返回响应
res.json({page:'api'})
})
// 5 在配置完所有路由以后,写一个错误处理中间件
// 语法:app.use((err,req,res,next)=>{})
// 要求:必须有四个参数,不能省略任何一个
// 第一个:错误信息
// 第二个:请求对象
// 第三个:响应对象
// 第四个:下一个中间件
app.use((err,req,res,next)=>{
// 在后端处理输出这个语法错误
// console.log(err)
// 给前端响应
res.json({help:'msg error'})
})
// 3 监听端口
app.listen(8080,()=>{
console.log('服务器开启成功')
})
2.express.static()
静态资源
- 语法:app.use(express.static(‘静态资源文件夹路径’))
- 资源中间件尽量放在所有路由配置的最前面
- 在路由匹配的时候
- 如果路由是/index.html
- 就先去静态资源文件夹的路径里面找index.html,找到了,直接返回响应,没找到就继续后面的路由匹配
- 静态资源中间件可以写多个,按顺序匹配
// 1 导入express
const express = require('express');
const path = require('path')
// 2 实例化express
const app = express();
// 需求
// public文件夹,里面是前端给我的html,js,css,img资源
// 文件夹里面的html文件,css文件,js文件,图片文件很多
// 如果我自己配置路由,每个文件都要配置一个路由
// 不难,但是很麻烦
app.get('/index.html',(req,res)=>{
res.sendFile(path.join(__dirname,'public','index.html'))
})
// 3 监听端口
app.listen(8080,()=>{
console.log('服务器开启成功')
})
var express = require('express')
var app = express()
app.use(function (req, res, next) {
console.log('Time:', Date.now())
next()
})
3.express.urlencoded
请求主体解析
express的post请求主体解析的内置中间件:bodyParser
- 在路由配置的最前面设置
- app.use(express.urlencoded())
- 解析 application/x-www-form-urlenocded格式的请求主体
- app.use(express.json())
- 解析application/json格式的请求主体
- 使用这个中间件以后
- 在后面的所有路由的请求对象中,就有req.body
- 就是解析好的请求主体
// 1 引入express
const express = require('express');
// 2 实例化express
const app = express();
// 使用bodyParser中间件
app.use(express.json())
app.use(express.urlencoded())
// 4 配置路由
app.post('/api',(req,res)=>{
console.log(req.body);// 解析好的请求主体
})
// 3 监听端口
app.listen(8080,()=>{
console.log('服务器开启成功')
})
4.router.use()
路由中间件
var express = require('express')
var app = express()
var router = express.Router()
// 没有路由的,是针对router的每一个请求
router.use(function (req, res, next) {
console.log('Time:', Date.now())
next()
})
// 针对动态路由 /user/:id
router.use('/user/:id', function (req, res, next) {
console.log('Request URL:', req.originalUrl)
next()
}, function (req, res, next) {
console.log('Request Type:', req.method)
next()
})
// 针对get方式的动态路由/user/:id
router.get('/user/:id', function (req, res, next) {
// if the user ID is 0, skip to the next router
if (req.params.id === '0') next('route')
// otherwise pass control to the next middleware function in this stack
else next()
}, function (req, res, next) {
// render a regular page
res.render('regular')
})
// 针对get方式的动态路由/user/:id
router.get('/user/:id', function (req, res, next) {
console.log(req.params.id)
res.render('special')
})
//在app上挂载router
app.use('/', router)