express框架
一.基本介绍
Express
是一个基于Node.js
平台,快速、开放、极简的 web 开发框架- web 开发: 对不同的请求能够显示页面;提供接口服务;
- 对于
node.js
来说,Express
是一个第三方模块,有丰富的 API 支持,强大而灵活的中间件特性 Express
不对Node.js
已有的特性进行二次抽象,只是在它之上扩展了 Web 应用所需的基本功能- 参考链接
- Express 官网 http://expressjs.com/
- Express 中文文档(非官方)http://www.expressjs.com.cn/
- Express GitHub仓库 https://github.com/expressjs/express
理解:
- 我们前面用
http模块
来支持web服务,写接口 ----- 原生js - 现在要用
express
来写web服务,写接口 ------ jQuery
二.运行第一个express程序
expresss
是一个第三方模块(在npm上可以下载),在使用它之前要先去下载它,在下载包之前要先创建项目,并通过npm init
创建package.json文件
。
1. 创建项目并初始化
创建一个空目录(learn-express)(目录名不要有汉字,也不是某个包的名字),在此目录下运行npm init
命令来生成package.json文件
# 在你的项目根目录下,打开小黑窗
# 1. 初始化 package.json 文件
npm init -y
2. 下载express包
参考文档:http://expressjs.com/en/starter/installing.html
# 2. 本地安装 express 到项目中
# npm install express
npm i express
注意:
- 项目目录名字不要取中文,也不要取express
- 如果安装不成功:
- 换个网络环境
- 运行下npm cache clean -f,再重新运行下载命令试试
3. 使用express快速创建web服务器
参考文档:http://expressjs.com/en/starter/hello-world.html
在项目根目录下新建一个js文件,例如app.js
,其中输入代码如下:
// 0. 加载 Express
const express = require('express')
// 1. 调用 express() 得到一个 app
// 类似于 http.createServer()
const app = express()
// 2. 设置请求对应的处理函数
// 当客户端以 GET 方法请求 / 的时候就会调用第二个参数:请求处理函数
app.get('/', (req, res) => {
res.send('hello world')
})
// 3. 监听端口号,启动 Web 服务
app.listen(3000, () => console.log('app listening on port 3000!'))
说明:
app.get('/')
相当于添加个事件监听:当用户以get方式求"/"时,它后面的回调函数会执行,其回调函数中的req
,res
与前面所学http模块
保持一致。
-res.send()
是exprss
框架给res对象补充提供的方法(http模块
中的res是没有这个方法的。),用于结束本次请求。类似的还有res.json()
,res.sendFile()
。- express 框架会增强req,res的功能
三.托管静态资源-web服务器
参考文档:http://expressjs.com/en/starter/static-files.html
让用户直接访问静态资源是一个web服务器最基本的功能。
http://localhost:3000/1.png
http://localhost:3000/css/style.css
http://localhost:3000/js/index.js
例如,如上url分别是请求一张图片,一份样式文件,一份js代码。我们实现的web服务器需要能够直接返回这些文件的内容给客户端浏览器。
在http模块
时,我们已经实现了这些功能了,但是要写很多代码,现在使用express框架
,只需一句代码就可以搞定了,这句代码是 express.static('public')
1. 忽略前缀
// 加载 Express
const express = require('express')
// 1. 调用 express() 得到一个 app
// 类似于 http.createServer()
const app = express();
// 2. 设置请求对应的处理函数
app.use(express.static('public'))
// 3. 监听端口号,启动 Web 服务
app.listen(3000, () => console.log('app listening on port 3000!'))
此时,所有放在public下的内容可以直接访问,注意,此时在url中并不需要出现public这级目录
- 在
public
下新建index.html
,可以直接访问到。
2. 限制前缀
// 限制访问前缀
app.use('/public', express.static('public'))
这意味着想要访问public
下的内容,必须要在请求url中加上/public
四.路由和接口
参考文档:http://expressjs.com/en/starter/basic-routing.html
路由(Routing
)是由一个 URL(或者叫路径标识)
和一个特定的HTTP 方法(GET、POST 等)
组成的,涉及到应用如何处理响应客户端请求。每一个路由都可以有一个或者多个处理器函数,当匹配到路由时,这些个函数将被执行。
1. 格式
const app = express();
// 定义路由
app.METHOD(PATH, HANDLER)
其中:
-
app
是express 实例
。(const app = express()
) -
METHOD
是一个 HTTP 请求方法。 全小写格式。如:post,get,delete
等 -
PATH
是请求路径(相当于在http模块中用到过的url.parse(req.url).pathname
)浏览器url 服务端路径 http://localhost:8080 / http://localhost:8080/public/a/index.html /public/a/index.html http://localhost:8080/index.html?a=1&b=2 /index.html -
HANDLER
是当路由匹配到时需要执行的处理函数(req,res)=>{ }
2. 写get接口
1) get无参数
const express = require('express');
const app = express();
app.get('/get', function(req, res) {
// 直接返回对象
res.json({ name: 'abc' });
});
app.listen('8088', () => {
console.log('8088');
});
注意:
-res.json()
是express
提供的方法。
2) get接口有参数
express框架
会自动收集get方式从url地址中传递的查询字符串参数
,并自动保存在req对象的query属性
中。我们直接来获取即可。
const express = require('express');
const app = express();
app.get('/get', function(req, res) {
// 直接返回对象
console.log(req.query);
res.send({ name: 'abc' });
});
app.listen('8088', () => {
console.log('8088');
});
注意:
req.query
属性是express框架
额外提供的属性。
3. 写post接口
post接口
与get请求不同在于:它的参数一般是通过请求体来传递的。根据传递的参数的格式不同,分成三种情况来说
- 传递普通键值对
- 传递form表单(涉及文件上传)
- 传递json
1) 普通键值对参数
具体来说当content-type
为x-www-form-urlencoded
时,表示上传的普通简单键值对 。如果通过postman测试的话,对应的设置如下:
步骤
// 1. 使用中间件
app.use(express.urlencoded());
app.post("/add",function(req,res){
//2. 可以通过req.body来获取post传递的键值对
res.json(req.body)
})
注意:
app.use(....)
之后,在res
中就会多出一个属性res.body
。extended: false
:表示使用系统模块querystring
来处理传入的参数,也是官方推荐的extended: true
:表示使用第三方模块qs
来处理传入的参数.
2) post接口-json格式的参数
在post传递参数时,如果要传入的参数比较复杂**(多级嵌套)**,则可以使用json格式
上传。
var data = {
name:"abc",
address:{
"a":1,
"b":2,
"info":"c"
}
}
postman操作
后端
app.use(express.json());
// 会自动加入req.body属性,这个属性中就包含了post请求所传入的参数
// 用来处理JSON格式的数据
app.post('/postJSON',(req,res)=>{
// 后端收到post传参
console.log(req.body);
res.send('/postJSON')
})
3) post接口-form-data文件上传
如果post涉及文件上传操作,则需要在服务器端额外使用第三方multer
这个包(不属于express
)来获取上传的信息。
Multer
是一个 node.js 中间件,用于处理multipart/form-data
类型的表单数据,它主要用于上传文件。
enctype="multipart/form-data"
对应postman的操作如下:
步骤
1.安装
npm install multer
2.使用
// 1. 引入包
const multer = require('multer');
// 2. 配置
const upload = multer({dest:'uploads/'}) // 上传的文件会保存在这个目录下
// uploads表示一个目录名,你也可以设置成其它的
// 3. 使用
// 这个路由使用第二个参数 .upload.single表示单文件上传, 'cover' 表示要上传的文件在本次上次数据中的键名。对应于前端页面上的:
// <input type="file" name='cover'/>
app.post("/postfile",upload.single('cover'), function(req,res){
// req.file 记录了文件上传的信息
// req.body 记录了其它普通参数(非文件)的信息
// 其它操作
})
说明:
- 如果当前目录下没有
uploads
,它会自动创建uploads这个文件夹
upload.single
只是处理了文件的上传。你仍可以通过req.body
来获取其它参数
五.理解接口传参
1.请求报文
我们一般使用ajax技术
向接口传参,按http协议
的约定,每个请求都有三个部分:
- 请求行: 保存了
请求方式
,地址
,可以以查询字符串
的格式附加一部分数据。 - 请求头:它可以附加很多信息,其中
content-type
用来约定请求体中保存的数据格式。
content-type常见有三种取值:
content-type的值 | 表示请求体的数据格式 | 示例 |
---|---|---|
application/x-www-form-urlencode | 普通键值对象 | a=2&c=1 |
application/json | json对象 | {a:1,b:{c:1}} |
multipart/form-data | 上传文件 | file |
- 请求体: 本次请求携带的参数。至于这些参数到了后端应该如何解析出来,由请求头中的
content-type
来决定。
2.传参途径
- 方法一:请求行。常见方式如下:
- 使用ajax技术,通过get方式传参。
- 在浏览器地址栏中输入
接口地址并补充上查询字符串
。
- 方法二:请求体
- ajax中的post, put, delete可以从
请求体
中进行传参。
- ajax中的post, put, delete可以从
另外,请求头中的content-type
用来告之服务器应该以何种方式去解析请求体中的数据。
3.后端处理
接口的规则是由后端来定的,它会约定接口的名字,参数,格式,方式。
名字: /api
参数:name: 用户名,pwd:密码,avatar头像文件。
格式:formdata.
方式:post
名字: /api2
参数:name: 用户名,pwd:密码
格式:application/x-www-form-encoded (普通键值对)
方式:post
名字: /api3
参数:name: 用户名,pwd:密码
格式:application/json
方式:post
总结
传参方式 | 前端 content-type | 后端框架express |
---|---|---|
请求行 | get方式 | req.query |
请求体 | application/x-www-form-urlencode | app.use(express.urlencoded()); req.body |
请求体 | application/json | app.use(express.json()); |
请求体 | multipart/form-data | 1. 引入包 const multer = require(‘multer’); 2. 配置app.post(’/apiname’, upload.single(), req.body) |
六.接口传参-整体示例
目录结构
-package.json
-node_modules
-public
-------index.html
-server.js
要求:
- localhost:3000/index.html可以访问public下的index.html文件
- 在后端实现三个接口,分别来处理在index.html中发出的post请求:只需要在后端接收到参数即可
前端
用jquery的ajax来发请求
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<button id="btn_keyvalue"> post-传递普通键值对</button>
<hr/>
<button id="btn_json"> post-传递json</button>
<hr/>
<form id="myform">
<input type="text" name="title">
<input type="file" name="cover">
</form>
<button id="btn_formdata">post-传递formdata</button>
<hr/>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script>
// 最普通的键值对格式
$('#btn_keyvalue').click(function(){
$.ajax({
type:'post',
url:'http://localhost:3000/post',
data:{a:1,b:2},
success(res){
console.log(res);
}
})
})
var obj = {
"name":"abc",
"address":{
"a":1,
"b":2,
"info":"c"
}
}
// 传递复杂的JSON对象数据
$('#btn_json').click(function(){
$.ajax({
type:'post',
url:'http://localhost:3000/postJSON',
// contentType: false,
contentType: "application/json; charset=UTF-8",
data: JSON.stringify(obj),
success(res){
console.log(res);
}
})
})
// 传formData表单数据
$('#btn_formdata').click(function(){
var fd = new FormData(document.getElementById('myform'));
$.ajax({
type:'post',
url:'http://localhost:3000/admin/article_publish',
contentType: false,
processData:false,
data:fd,
success(res){
console.log(res);
}
})
})
</script>
</body>
</html>
后端
// 实现get接口
const express = require('express')
const app = express();
//静态资源托管
app.use(express.static('public'))
// 使用包. 则在后续的post请求中
// 会自动加入req.body属性,这个属性中就包含了post请求所传入的参数
// 处理普通的键值对格式
// Content-Type: application/x-www-form-urlencoded
app.use(express.urlencoded())
// 处理JSON格式
// Content-Type: application/json;
app.use(express.json())
// 引入multer包
const multer = require('multer');
// 配置一下multer
// 如果本次post请求涉及文件上传,则上传到uploads这个文件夹下
// Content-Type: multipart/form-data;
var upload = multer({ dest: 'uploads/' })
// formDate
app.post('/admin/article_publish',upload.single('cover'),(req,res)=>{
//upload.single('cover')
// 这里的cover就是在页面中表单元素中的name
// <input type="file" name="cover" />
// 把要上传文件放在指定的目录
console.log(req.file);
// 其它参数,还是在req.body中找
console.log(req.body);
res.json({code:200,msg:'上传成功',info:req.file.path})
})
// 普通post 键值对
app.post('/post',(req,res)=>{
// 希望在后端收到post传参
console.log(req.body);
let obj = req.body
obj._t = Date.now();
res.json(obj)
})
// 用来JSON格式的数据
// Content-Type: application/json;
app.post('/postJSON',(req,res)=>{
// 希望在后端收到post传参
console.log(req.body);
// res.send('/postJSON')
res.json( req.body )
})
// 实现接口,返回所传入的参数,并附上上时间戳
app.get('/getapi',(req,res)=>{
// 通过 req.query快速获取传入的参数
console.log(req.query);
let obj = req.query
obj._t = Date.now();
res.json( obj )
})
app.listen(3000,()=>{
console.log('express应用在3000端口启动了');
})