express是一个创建服务器的第三方模块,比内置http模块使用方便,使用它还是老套路先安装后导入。
npm i express
创建一个简单的服务器:
//导入
const express = require('express')
// 创建app
const app = express()
// 监听get post
app.get('/user',(req,res)=>{
// req:请求体对象
// res:响应体对象
// req.url 获取请求地址
// req.method 获取请求方法
// req.params 获取动态参数
// req.query 获取url地址上的参数
// res.send()向客户端响应数据
app.send('GET user')
})
app.post('/book',(req,res)=>{
res.send('POST book')
})
// 使用80端口
app.listen(80,()=>{
console.log('http://127.0.0.1')
})
express中自带一个中间件方法 express.static(目录名) 就可以把这个目录设置为静态资源目录,这里的中间件后面会说到,现在就把它当成一个方法就行。
//导入
const express = require('express')
// 创建app
const app = express()
// 使用app.use方法
app.use(express.static('public'))
// app.use('/public',express.static('public')) // 如果想要添加前缀的话需要在 app.use 中传入第一参数为 '/public'
// 使用80端口
app.listen(80,()=>{
console.log('http://127.0.0.1')
})
静态资源目录中的文件可以直接在服务器上访问,比如 public 目录下有一个 style.css 文件,就可以在服务器地址上直接写 http://127.0.0.1/style.css,就可以访问到,其中不需要在 /style.css 前面添加 /public 前缀,如果想要添加前缀的话需要在 app.use 中传入第一参数为 ‘/public’。
路由就是当客户端发送请求时,服务器会根据请求方法和地址匹配对应的处理方法。express提供了一个路由的中间件 express.Router()。写路由最好使用模块化,这样容易维护。下面演示路由的使用:
// 新建一个user.js文件 关于user的请求都在这个文件
const express = require('express')
const router = express.Router()
router.get('/list',(req,res)=>{
res.send('GET user list')
})
// 导出
module.exports = router
// app.js
const express = require('express')
// 导入路由模块
const router = require('./router/user')
// 创建app应用
const app = express()
// 设置静态资源
app.use(express.static('public'))
// 注册路由
app.use('/user',router)
// 设置端口号
app.listen(80, () => {
console.log('app is running at http://127.0.0.1')
})
/**
* app.use()作用注册全局中间件
*/
在 app.use() 时传入一个前缀,客户端请求时必须填写前缀,app.use() 的作用就是注册全局中间件
中间件相当于拦截了请求,就是客户端请求时会先进入中间件函数处理之后最后到路由处理之后返回响应数据,之前使用app.use() 的方法都是全局中间价,中间件其实就是函数但它有个参数 next 可以进行下一个中间件,比如:
const express = require('express')
const app = express()
// 定义全局中间件
app.use((req, res, next) => {
console.log('我是第一个中间件')
next()
})
app.use((req, res, next) => {
console.log('我是第二个中间件')
next()
})
// 路由
/**
* 每个路由都会经过两个中间价
*/
app.get('/user', (req, res) => {
console.log(' get user ')
res.send('get ')
})
app.listen(80, () => {
console.log('http://127.0.0.1')
})
只要发送请求就会进入中间件1然后进入中间件2最后到路由,中间件和路由的req,res是共享的,这样就可以通过中间件对请求的数据处理后添加到req上路由就可以拿到处理后的数据,**post请求想要拿到请求的参数有些复杂,但经过中间件处理后就可以在路由中通过req.body拿到参数。**下面演示局部中间件:
const express = require('express')
const app = express()
// 定义中间价 不使用app.use()
function fn1(req, res, next) {
console.log('我是第一个中间价')
next()
}
function fn2(req, res, next) {
console.log('我是第二个中间价')
next()
}
// 定义路由
/** 局部使用
* 使用多个中间价用数组或 ,号隔开
*/
// 没有使用中间件
app.get('/test1', (req, res) => {
res.send('Get test1')
})
// 使用了中间件
app.get('/test2', [fn1, fn2], (req, res) => {
res.send('Get test2')
})
app.listen(80, () => {
console.log('http://127.0.0.1')
})
局部中间件是不用app.use() 的,我们可以通过路由是否使用中间件,很简单就是在设置路由中添加参数为中间件就可以了。
使用中间件的注意点:
中间件的分类:
前两类很好理解,下面看错误级别的中间件:
const express = require('express')
const app = express()
app.get('/', (req, res) => {
throw new Error('服务器请求错误')
res.send('home Page')
})
// 定义错误级别的中间价 !!!一定在路由之后注册
app.use((err, req, res, next) => {
console.log('发生了错误' + err)
res.send('Error!' + err)
})
app.listen(80, () => {
console.log('http://127.0.0.1')
})
错误级别的中间件有个特点就是多一个 err 参数,err参数存的就是路由发生错误的信息,注意哦!!!它一定要写在路由下面。
内置中间件就是express自带的,分别是:
第一个已经了解了,下面对后两个进行演示:
/**
* express.static(path) : 添加静态资源目录
* express.json() :处理json字符串的请求体数据
* express.urlencoded() : 处理url中encoded格式的请求体数据
*/
const express = require('express')
const app = express()
// 处理json格式的中间价
app.use(express.json())
// 处理 urlencoded 格式中间件
app.use(express.urlencoded({ extended: false }))
// json格式请求数据
app.post('/user', (req, res) => {
console.log(req.body) // 如果没有中间件处理请求的数据默认是undifand
res.send('ok')
})
// urlencoded格式请求数据
app.post('/book', (req, res) => {
console.log(req.body)
res.send('ok')
})
app.listen(80, () => {
console.log('http://127.0.0.1')
})
最后两个就是对post请求获取参数的处理,将处理好的参数放到req.body属性上,一个处理json格式的数据,另一个处理urlencoded格式的数据。后续的路由中就可以使用req.body上取出请求的参数
接下来认识以下第三方中间件 body-parser 这个也是处理请求参数的和 express自带的中间价很相似,要使用它老套路先安装,直接演示:
npm i body-parser
const express = require('express')
const parser = require('body-parser')
const app = express()
/**
* parser.json() 处理json
* parser.urlencoded({extended:false}) 处理urlencoded格式
*/
app.use(parser.urlencoded({ extended: false }))
app.post('/user', (req, res) => {
console.log(req.body)
res.send('ok')
})
app.listen(80, () => {
console.log('http://127.0.0.1')
})
和express自带的中间价用法一样,就不多说了。
接口其实就是在写路由接下来写几个简单的接口,开始之前先准备搭建项目目录 ,我这次使用 yarn 管理。
新建一个目录进入目录使用如下命令:
mkdir myExpress
cd myExpress
yarn init -y
安装express
yarn add express
构建目录结构 :
|-- node_modules
|-- src
|-- router
|-- apiRouter.js
|-- app.js
|-- package.json
|-- yarn.lock
在app中搭建服务器:
// app.js
const express = require('express')
const app = express()
// 导入路由模块
const router = require('./router/apiRouter')
// 使用中间件
app.use(express.json())
app.use(express.urlencoded({ extended: false }))
// 注册路由
app.use('/api', router)
app.listen(80, () => {
console.log('http://127.0.0.1')
})
然后去创建路由:
// router/apiRouter.js
const express = require('express')
const router = express.Router()
// 编写get接口
router.get('/get', (req, res) => {
const query = req.query
res.send({
status: 0, //0表示处理成功 1表示处理失败
msg: 'GET 请求成功', // 状态描述
data: query // data响应给客户端的数据
})
})
// 编写post接口
router.post('/post', (req, res) => {
const body = req.body
res.send({
status: 0,
msg: 'POST 请求成功',
data: body
})
})
router.delete('/delete', (req, res) => {
const body = req.body
res.send({
status: 0,
msg: 'DELETE 请求成功',
data: body
})
})
module.exports = router
这里编写3个接口,get、post、delete后面会说明delete接口,get、post是常用的一个是获取数据,一个是向服务器提交数据。启动app.js文件就可以使用 postman 向 http://127.0.0.1 发送请求,得到数据。
之前编写的接口,会存在跨域问题导致无法在html文件中获取数据,解决这个问题有两种方法,一、CORS中间件,二、JSONP。JSONP支持GET请求,不支持其他请求所以不推荐使用,接下来使用CORS中间件解决跨域问题。
安装CORS中间件
yarn add cors
配置cors,向app.js中添加几行代码即可。
// app.js
// app.js
const express = require('express')
const app = express()
// ++
const cors = require('cors')
// 导入路由模块
const router = require('./router/apiRouter')
// 使用中间件
// ++
app.use(cors())
app.use(express.json())
app.use(express.urlencoded({ extended: false }))
// 注册路由
app.use('/api', router)
app.listen(80, () => {
console.log('http://127.0.0.1')
})
这样我们发送请求就不会出现跨域问题,也能得到服务器发送过来的数据
拿不到数据其实就是,请求发送了服务器也返回了数据而浏览器拒绝了而已,就是没有设置请求头,下面了解一些请求头:
// 请求头的设置格式都是通过res
// res.setHeader(key,value)
// Access-Control-Allow-Origin: | *
// 用来设置指定哪些网站可以请求服务器
// res.setHeader('Access-Control-Allow-Origin','*') 表示任意网站都可以请求
// res.setHeader('Access-Control-Allow-Origin','http://qwe.cn') 表示只允许http://qwe.cn可以请求服务器
// Access-Control-Allow-Headers
// 用来设置额外的请求头信息的声明
// res.setHeader('Access-Control-Allow-Headers','Content-type','X-Custom-Header')
// 表示允许设置Content-type和X-Custom-Header请求头
// Access-Control-Allow-Methods
// res.setHeader('Access-Control-Allow-Methods','GET','POST','HEAD','DELETE')
// 表示允许客户端使用 get post delete head方式发送请求
// res.setHeader('Access-Control-Allow-Methods','*') 表示所有
以上请求头了解即可,cors资源共享有两种请求方式:
简单请求的方式get,post,haed,三者之一,http头部信息不能出现没有定义的头部字段。
预检请求的方式就是除了简单请求的3种方式之外都是,响应头是包含自定义头部字段的,向服务器发送了application/json格式数据。
客户端发送请求时浏览器 会先发送 OPTION 请求进行预检,判断服务器是否允许这样的请求,只有通过了才会返回真实数据,这就是前面写了一个delete接口,这种预检请求会发送两次请求,先预检,在发送真实请求。