express

141 阅读8分钟

安装

npm i express@4.17.1

文档

express中文网

创建基本服务器

//导入express
const express = require('express')

//创建服务器实例
const App = express()

//开启服务器
App.listen(80,()=>{
    console.log('server running http://127.0.0.1')
})

监听GET POST请求 响应客户端

//导入express
const express = require('express')

//创建服务器实例
const App = express()

// 监听GET POST请求 响应客户端请求内容
// App.get('请求地址', (req,res)=>{函数体})

App.get('/user', (req,res)=>{
  //调用 res.send()方法向客户端响应一个JSON对象
  res.send({ name: "zhangsan" });
})

App.post('/user', (req,res)=>{
    //向客户端响应一段文本
    res.send('请求成功')
})

//开启服务器
App.listen(80,()=>{
    console.log('server running http://127.0.0.1')
})

获取URL携带的查询参数

         
App.get('/',(req,res)=>{
  //req.query() 获取URL中的查询参数\
  //默认情况下req.query是一个空对象
 console.log(req.query); 
 res.send(req.query)
})


//输出
{
    "name": "zs",
    "age": "20"
}

获取URL中的动态参数

##
//获取URL中的动态参数 :id
App.get('/user/:id/:name',(req,res)=>{
    // req.params 可以获得URL中的动态参数
    //默认是一个空对象
    console.log(req.params)
    res.send(req.params)
})

//输出
{
    "id": "1",
    "name": "luo"
}

托管静态资源

//托管静态资源         要托管的文件路径 
//可多次调用托管多个文件
App.use(express.static('../clock'));

express路由

  • 简单的路由
//最简单的路由
const express = require('express')

const app = express()

app.get('/',(req,res)=>{
    res.send({message:'Hello World GET'})   
})

app.post('/',(req,res)=>{
    res.send('hello POST'); 
})
app.listen(80,(req,res)=>{
    console.log('server running at http://127.0.0.1')
})
  • 模块化路由
  • 创建路由模块文件并导出
const express = require('express')

const router = express.Router()


router.get('/user/list',(req,res)=>{
    res.send('user info list GET')
})

router.post('/user/add',(req,res)=>{
    res.send('user info add POST')
})


// 导出
module.exports =  router
  • 模块化路由
const express = require('express')

const app = express()

//导入模块路由
const router = require('./router/userinfo')

// 注册路由模块
app.use(router)


// 注册路由模块 并使用统一的请求前缀
app.use('/api',router)


app.listen(80, ()=>{
    console.log('server running at http://127.0.0.1')
})

中间件

  • 当一个请求到达Express服务器之后可以连续调用多个中间件从而对这次请求进行预处理
  • Expoerts 本质上就是一个function处理函数
  • 中间件的形参列表中 必须包含next参数 而路由处理函数只包含req和res
  • next函数是实现多个中间件连续调用的关键 他表示把流转关系转交给下一个中间件或路由
  • 客户端发起任何请求到达服务器之后都会触发的中间件 叫做全局生效的中间件
  • ==中间件注意事项;==
  • 在注册路由之前注册中间件(错误级别中间件除外)
  • 中间件可连续调用多个
  • 别忘记调用 next() 函数next() 函数后别写代码
  • 多个中间件共享 req、 res对象
const express = require('express')

const app = express()


//局部中间件
const wm = function(req,res,next){
    console.log('我是第一个局部中间件')
    next()
}
const wm2 = function (req, res, next) {
  console.log("我是第二个局部中间件");
  next();
};

//全局中间件简化写法
app.use(function(req,res,next){
    //获取请求到达服务器的时间  
    const time = Date.now()
    //为req挂载自定义属性 从而把时间共享给后面的 所有路由
    req.time=time;
    next()
})

//使用局部中间件 多个使用[wm1,wm2]
app.get('/', [wm,wm2],(req,res)=>{
  //共享  req 数据
    res.send('Home Page' + req.time)
})
app.get("/user", (req, res) => {
  res.send("User Page" + req.time);
});

app.listen(80, ()=>{
    console.log('server running at http://127.0.0.1')
})

中间件分类

  • ==应用级别的中间件==

  • 通过 app.use() 或 app.get() 或 app.post() ,绑定到 app 实例上的中间件

  • ==路由级别的中间件==

  • 绑定到 express.Router() 实例上的中间件,叫做路由级别的中间件。用法和应用级别中间件没有区别。应用级别中间件是绑定到 app 实例上,路由级别中间件绑定到 router 实例上。

  • ==错误级别的中间件==

  • 用来捕获整个项目中发生的异常错误,从而防止项目异常崩溃的问题

  • 错误级别中间件的处理函数中,必须有 4 个形参,形参顺序从前到后分别是== (err, req, res, next) 。==

  • 错误级别的中间件必须注册在所有路由之后

const express = require('express')

const app = express()

//局部中间件
const wm = function(req,res,next){
    console.log('我是第一个局部中间件')
    next()
}
const wm2 = function (req, res, next) {
  console.log("我是第二个局部中间件");
  next();
};

//全局中间件简化写法
app.use(function(req,res,next){
    //获取请求到达服务器的时间
    const time = Date.now()
    //为req挂载自定义属性 从而把时间共享给后面的 所有路由
    req.time=time;
    next()
})

//使用局部中间件 多个使用[wm1,wm2]
app.get('/', [wm,wm2],(req,res)=>{
    //人为制造错误
    throw new Error('服务器出现了异常')
    res.send('Home Page' + req.time)
})
app.get("/user", (req, res) => {
  res.send("User Page" + req.time);
});

//定义错误中间件
app.use((err,req,res,next)=>{
    console.log('发生了错误' + err.message)
    res.send('Error:' + err.message)
})

app.listen(80, ()=>{
    console.log('server running at http://127.0.0.1')
})
  • ==Express 内置中间件==
  • 自 Express 4.16.0 版本开始,Express 内置了 3 个常用的中间件,极大的提高了 Express 项目的开发效率和体验:
  • express.static 快速托管静态资源的内置中间件,例如: HTML 文件、图片、CSS 样式等(无兼容性)
  • express.json 解析 JSON 格式的请求体数据(有兼容性,仅在 4.16.0+ 版本中可用)
  • express.urlencoded 解析 URL-encoded 格式的请求体数据(有兼容性,仅在 4.16.0+ 版本中可用)
//配置解析application./json格式数据的内置中间件
app.use(express.json())
//配置解析application/.x-www-form-urlencoded格式数据的内置中间件
app.use(express.urlencoded({ extended: false }))

自定义中间件

const express = require('express')

const app = express()

//导入内置的处理querstring的内置模块
const qs = require('querystring')

//这是解析表单的中间件
app.use((req,res,next)=>{
    //定义 str 用来存储接收的请求数据
    let str = ''
    //监听req的data事件
    req.on('data',(chunk)=>{    
        //将chunk转换为字符串,并追加到str后面
        str += chunk
    })

    //监听req的end事件
    req.on('end',()=>{
      //todo 把字符串格式的数据解析成对象格式
      //调用 qs.parse() 方法将查询字段解析成对象格式
      const body = qs.parse(str);
      //在str中存放的是完整的请求体数据
      console.log(body);
      //将解析出来的数据挂载为req.body 供下游使用
      req.body=body
      res.send(req.body)
      next()
    })

})

app.post('/user',(req,res)=>{
    res.send('success')
})

app.listen(80, ()=>{
    console.log('server running at http://127.0.0.1')
})

API接口

  • GET
  • POST
//路由模块文件
const express = require("express");

const router = express.Router();

router.get("/get", (req, res) => {
  //通过req.query 拿到查询的参数
  const query = req.query

  res.send({
    status: 0, //0表示成功 1表示处理失效
    msg: "GET 请求成功", //状态描述
    data: query, //响应客户端数据
  });

});

router.post('/post', (req,res)=>{
    //調用req.body 獲取請求體數據
    const body = req.body
    //响应客户端请求数据
    res.send({
        status: 0, //0 成功 1 失败
        msg: "POST 请求成功",
        data: body //响应的具体数据
    })
})

module.exports = router;

//服务器模块文件
const express = require('express')

const app = express()

//导入路由模块
const router = require('./apiRouters')

//配置处理JSON格式和URL-encodeed 格式的中间件
app.use(express.json())
app.use(express.urlencoded({extended:false}))

//注册路由添加统一 的前缀
app.use('/api',router)

app.listen(80, ()=>{
    console.log('server running at http://127.0.0.1')
})

跨域问题

  • 使用cors解决跨域问题
//安装
npm install cors

//导入
const cors = require('cors')

//注册
app.use(cors())
  • CORS(Cross-Origin Resource Sharing,跨域资源共享)解决跨域,是通过 HTTP 响应头决定浏览器是否阻止前端 JS 代码跨域获取资源
  • 浏览器的同源安全策略默认会阻止网页“跨域”获取资源。但如果接口服务器配置了 CORS 相关的 HTTP 响应头,就可解除浏览器端的跨域访问限制
  • CORS 主要在服务器端进行配置。客户端浏览器无须做任何额外的配置,即可请求开启了 CORS 的接口。
  • CORS 在浏览器中有兼容性。只有支持 XMLHttpRequest Level2 的浏览器,才能正常访问开启了 CORS 的服务端接口(例如:IE10+、Chrome4+、FireFox3.5+)。

CORS 常见响应头

  • ==Access-Control-Allow-Origin==:制定了允许访问资源的外域 URL
//只允许http://bruceblog.io域名的请求
res.setHeader('Access-Control-Allow-Origin', 'http://bruceblog.io')
//允许任意域的请求
res.setHeader('Access-Control-Allow-Origin', '*')
  • 默认之支持客户端向服务器发送如下九个请求头

  • Accept、Accept-Language、

  • Content-Language、

  • DPR、Downlink、Save-Data、Viewport-Width、Width 、

  • Content-Type (值仅限于 text/plain、multipart/form-data、application/x-www-form-urlencoded 三者之一)

  • 如果客户端向服务器发送了额外的请求头信息,

  • 则需要在服务器端,通过== Access-Control-Allow-Headers ==对额外的请求头进行声明,否则这次请求会失败!

res.setHeader('Access-Control-Allow-Headers', 'Content-Type, X-Custom-Header')
  • 默认情况下,CORS 仅支持客户端发起 GET、POST、HEAD 请求。如果客户端希望通过 PUT、DELETE 等方式请求服务器的资源,
  • 则需要在服务器端,通过 ==Access-Control-Alow-Methods== 来指明实际请求所允许使用的 HTTP 方法
//只允许POST, GET, DELETE, HEAD请求
res.setHeader('Access-Control-Allow-Methods', 'POST, GET, DELETE, HEAD')
//允许所有方式的请求
res.setHEader('Access-Control-Allow-Methods', '*')

CORS 请求分类

  • 简单请求
  • 请求方式:GET、POST、HEAD 三者之一
  • HTTP 头部信息不超过以下几种字段:==无自定义头部字段==、Accept、Accept-Language、Content-Language、DPR、Downlink、Save-Data、Viewport-Width、Width 、Content-Type(只有三个值 application/x-www-formurlencoded、multipart/form-data、text/plain)
  • 预检请求
  • 请求方式为 GET、POST、HEAD 之外的请求 Method 类型
  • 请求头中==包含自定义头部字段==
  • 向服务器发送了 application/json 格式的数据
  • 在浏览器与服务器正式通信之前,浏览器会==先发送 OPTION 请求进行预检==,以获知服务器是否允许该实际请求,所以这一次的 ==OPTION 请求称为“预检请求”==。服务器成功响应预检请求后,才会发送真正的请求,并且携带真实数据

JSONP接口

  • 概念: 浏览器端通过标签的src属性 请求服务器上的数据同时服务器返回一个函数的的调用这种请求数据的方式叫做jsonp

  • JSONP 不属于真正的Ajax请求

  • JSONP仅支持 GET请求

  • 注意事项

  • 如果项目中已经配置了CORS跨域资源共享,

  • 为了防止冲突,==必须在配置CORS中间件之前声明SONP的接口。==

  • 否则JSONP接口会被处理成开启了CORS的接口。