zoukankan      html  css  js  c++  java
  • Express

    1. 初识Express

    1.1 Expres简介

    1. 什么是 Express

      • 概念:Express 是基于 Node.js 平台,快速、开放、极简的 Web 开发框架。
      • 本质:第三方包,提供了快速创建 Web 服务器的便捷方法。
    2. Express 的作用
      对于前端来说,最常见的两种服务器,分别是:

      • Web 网站服务器:专门对外提供web网专资源的服务器。
      • API接口服务器:专门对外提供API接口的服务器。

      使用 Express,可以方便、快速创建Web网站的服务器或API接口的服务器。

    1.2 Express的基本使用

    1. 运行 npm i express@4.17.1 命令安装 express

    2. 创建基本的Web服务器

      // 1. 导入 express  
      const express = require('express');
      // 2. 创建 Web 服务器实例对象  
      const app = express();
      // 3. 定义端口号  
      const port = 3000;
      
      // 4. 调用app.listen(端口号,启动成功后的回调函数) 方法,启动服务器
      app.listen(port, () => {
          console.log('Express server running at http://127.0.0.1:3000');
      })
      
    3. 监听GET请求语法格式

      /*
       * @alias app.get(url, callback)
       * @param {string} 客户端请求的URL地址
       * @param {callback} 响应客户端请求的处理函数
       */
      app.get('url', (req, res) => {
          // req: 请求对象(包含了与请求相关的属性与方法)
          // res: 相应对象(包含了与响应相关的属性与方法)
          // 处理函数体
      })
      
    4. 监听POST请求语法格式

      /*
       * @alias app.post(url, callback)
       * @param {string} 客户端请求的URL地址
       * @param {callback} 响应客户端请求的处理函数
       */
      app.post('url', (req, res) => {
          // req: 请求对象(包含了与请求相关的属性与方法)
          // res: 相应对象(包含了与响应相关的属性与方法)
          // 处理函数体
      })
      
    5. 获取URL中携带的查询参数
      通过 req.query 对象,可以访问到客户端通过查询字符串的形式发送到服务器的参数:

      app.get('/search', (req, res) => {
         // req.query 默认是一个空对象
         // 当客户端的请求URL为:/search?q=taobao
         console.log(req.query); // 输出: { q: 'taobao' }
         console.log(req.query.q); // 输出: taobao
      })
      
    6. 获取表单中的数据
      通过 req.body 对象,可以获取表单提交过来的数据:

      // 如果需要使用 req.body , 需要在使用前使用解析表单的中间件(下面会详细说)
      app.use(express.urlencoded({ extended: true }));
      // 如果使用上述代码,req.body 的值为 undefined  
      app.post('/reg', (req, res) => {
         console.log(req.body);
      })
      
    7. 获取URL中的动态参数
      通过 req.params 对象,可以访问到URL中通过 : 匹配到的动态参数:

      // :id 表示 id 这个参数是动态参数  
      app.get('/user/:id', (req, res) => {
         // req.params 默认是一个空对象
         // 客户端请求URL为: /user/34
         console.log(req.params); // 输出: { id: '34' }
      })
      
    8. 响应客户端请求
      通过 res.send() 方法,可以把数据和信息发送给客户端。

      app.get('/', (req, res) => {
         // 向客户端发送 JSON 对象
         res.send({
            name: 'xao',
            age: 18,
            sex: '男',
         });
      })
      
      app.post('/user', (req, res) => {
         // 向客户端发送文本内容
         res.send('POST请求成功');
      })
      

    1.3 托管静态资源

    • 静态资源目录树结构
      |--public
      |--|--index.html
      |--|--login.html
      |--|--register.html
      
    1. express.static()
      通过使用 express.static() 方法,可以快速创建一个静态资源服务器。

      app.use(express.static('./public'));
      // 通过上述代码,客户端就可以访问public目录下的静态资源
      // htpp://127.0.0.1:3000/index.html
      // htpp://127.0.0.1:3000/login.html
      // htpp://127.0.0.1:3000/register.html
      
    2. 托管多个静态资源目录
      如果要托管多个静态资源目录,请多次调用express.static() 方法

      app.use(express.static('./public'));
      app.use(express.static('./files'));
      

      客户端访问静态资源时,express.static() 函数会根据目录的添加顺序查找所需的文件。

    3. 挂载路径前缀
      如果希望在托管的静态资源访问路径之前,挂载路径前缀,则可以使用如下的方式:

      app.use('/public',express.static('./public'));
      // 添加上述代码后,客户端访问资源时必须要带有 /public 前缀地址来访问public目录中的静态资源
      // htpp://127.0.0.1:3000/public/index.html
      // htpp://127.0.0.1:3000/public/login.html
      // htpp://127.0.0.1:3000/public/register.html
      

    2. Express 路由

    2.1 路由的概念

    1. 从广义上来讲,路由就是映射关系。

    2. express 中的路由

      • 在 express 中,路由指的是 客户端的请求服务器处理函数 之间的映射关系。
      • express 中的路由分 3 部分组成,分别是 请求的类型请求的 URL 地址处理函数
    3. 具体代码

      // 匹配GET请求,且请求 URL 地址为 /index.html  
      app.get('/index.html', (req, res) => {
         res.send('hello world !');
      })
      
      // 匹配POST请求,且请求 URL 地址为 /login.html  
      app.post('/login.html', (req, res) => {
         res.send('登录成功');
      })
      
    4. express路由匹配过程

      • 每当一个请求到达服务器之后,需要先经过路由的匹配,只有匹配成功之后,才会调用对应的处理函数。
      • 在匹配时,会按照路由定义的顺序进行匹配,如果请求类型和请求的 URL 同时匹配成功,则 Express 会将这次请求,转交给对应的 function 函数进行处理。

    2.2 路由的使用

    1. 简单使用方法
      将路由挂载到服务器实例对象上

      // 导入 express 
      const express = require('express')
      // 创建 web 服务器实例对象
      const app = express()
      // 定义端口号
      const port = 3000
      
      // 挂载路由
      app.get('/', (req, res) => {
         res.send('GET request to the homepage')
      })
      app.post('/', function (req, res) {
         res.send('POST request to the homepage')
      })
      
      // 启动服务器
      app.listen(port, () => {
         console.log(`Express server running at http://127.0.0.1:3000`)
      })
      
    2. 模块化路由
      为了方便对路由进行模块化的管理,Express 不建议将路由直接挂载到 app 上,而是推荐将路由抽离为单独的模块。

      1. 将路由抽离为单独模块的步骤如下:

        1. 创建路由模块对应js文件
        2. 调用 express.Router() 函数创建路由对象
        3. 定义路由的具体映射关系
        4. 使用 module.exports 向外共享路由对象
        5. 使用 app.use() 函数注册路由模块
      2. 代码如下

        • 创建路由模块
          // 导入 express 
          const express = require('express');
          
          //创建路由对象 
          const router = express.Router();
          
          // 定义路由的映射关系
          router.get('/', (req, res) => {
            res.send('GET request to the homepage')
          })
          router.post('/', function (req, res) {
            res.send('POST request to the homepage')
          })
          
          // 向外共享路由对象
          module.exports = router;
          
        • 注册路由模块
          // 导入路由模块
          const router = require('./router.js');
          // 使用 app.use() 注册路由模块  
          app.use(router);
          
        • 为路由模块添加路径前缀
          // 使用 app.use() 注册路由模块,并统一添加访问路径前缀  
          app.use('/index', router);
          

    3. Express 中间件

    3.1 中间件的概念

    1. 中间件(Middleware ),特指业务流程的 中间处理环节

    2. express 中间件的调用流程

      1. 当一个请求到达服务器之后,可以连续调用多个中间件,从而对这次请求进行预处理。
      2. 多个中间件之间共享 req 和 res 对象。
      3. 当处理完毕后,响应客户端的请求。

    3.2 中间件的类型

    1. 应用层中间件
      通过 app.use() 和 app.METHOD() 函数,绑定到 express() 实例对象上的中间件,叫做应用层中间件。

      const app = express();
      // 每次收到请求,都会执行该中间件(全局中间件)
      app.use((req, res, next) => {
         console.log('hello express !');
         next();
         // next() 方法必须被调用,以便进入下一个中间件。否则,请求将被挂起。
         // 调用 next() 方法之后,不要再书写任何代码。(一般最后调用 next() 方法)
      })
      // 该中间件只会在客户端请求 /api 路径时,被执行
      app.use('/api', (req, res, next) => {
         console.log('api');
         next();
      })
      // 该中间件只会在客户端发起 GET 请求,且请求 /public 路径时被执行
      app.get('/public', (req, res, next) => {
         console.log('public');
         next();
      })
      
    2. 路由级中间件
      路由器级中间件与应用层中间件的工作方式相同,只不过它绑定到的实例 express.Router() 上。

      const userRouter = express.Router();
      // 该中间件只会在客户端请求 userRouter 模块时被执行
      userRouter.use((req, res, next) => {
         console.log('success');
         next();
      })
      // 该中间件只会在客户端请求 userRouter 模块,且请求路径为 /userinfo 时被执行
      userRouter.use('/userinfo', (req, res, next) => {
         console.log('userinfo');
         next();
      })
      // 该中间件只会在客户端请求 userRouter 模块,发起 POST 请求,且路径为 /userinfo/update 时被执行
      userRouter.post('/userinfo/update', (req, res, next) => {
         console.log('update userinfo');
         next();
      })
      
    3. 错误处理中间件

      • 错误中间件必须带有4个参数,(err, req, res, next)
      • 错误中间件无需调用 next() 方法,但参数必须传;否则,会被当做其他类型的中间件执行。
      • 错误中间件必须在所有路由之后调用
      app.use((err, req, res, next) => {
         if(req.url == '/api/info') {
            return res.status(404).send('404 页面不存在!');
         }
         res.status(500).send('服务器内部错误');
      })
      
    4. 内置中间件

      • express.static 快速托管静态资源的内置中间件,例如: HTML 文件、图片、CSS 样式等(无兼容性)。
      • express.json 解析 JSON 格式的请求体数据(有兼容性,4.16.0+ 中可用)。
      • express.urlencoded 解析 URL-encoded 格式的请求体数据(有兼容性,4.16.0+ 中可用)。
    5. 第三方中间件(与包类似)

      • 非express官方内置的中间件,而是有第三方开发出来的express中间件,叫做第三方中间件。
      • 使用第三方中间件时,需要使用 npm i 名称 下载第三方中间件,使用 require() 导入,并调用 app.use() 挂载第三方中间件。

    3.3 自定义中间件

    // 新建一个js文件
    // 自定义模块可以使用 node.js 内置模块 或 第三方模块  
    
    // 定义中间件
    const myMiddle = (req, res, next) => {
       // 要执行的代码...
       next();
    }
    
    // 向外共享myMiddle
    module.exports = myMiddle;
    

    4. 使用过 express 搭建API接口服务器

    4.1 使用过 express 搭建API接口

    1. 搭建基本服务器

      // 导入 express
      const express = require('express');
      // 创建服务器实例对象
      const app = express();
      // 定义端口号
      const port = 3000;
      
      // 导入路由模块
      const apiRouter = require('./apiRouter');
      
      // 将路由模块注册到服务器上
      app.use('/api', apiRouter);
      
      app.listen(port, () => console.log(`Example server running at http://127.0.0.1:3000`));
      
    2. apiRouter 模块

      // 导入 express
      const express = require('express');
      // 创建一个新的路由对象
      const router = express.Router();
      
      // 实现路由的映射
      router.get('/get', (req, res) => {
         const query = req.query;
         res.send({
            status: 200, // 响应状态码:200
            msg: 'GET请求成功', // 响应状态描述
            data: query, // 响应给客户端的数据
         });
      });
      
      router.post('/post', (req, res) => {
         const query = req.query;
         res.send({
            status: 200, // 响应状态码:200
            msg: 'POST请求成功', // 响应状态描述
            data: query, // 响应给客户端的数据
         })
      })
      // 向外共享路由模块
      module.exports = router;
      

    4.2 跨域资源共享

    1. CORS(Cross-Origin Resource Sharing)跨域资源共享

      1. 同源:客户端请求的URL地址与服务器的ULR地址的协议域名端口号都相同即为同源,三者有一者不同为跨域。
      2. 由于浏览器同源策略的存在,默认阻止跨域获取资源;但服务器可以通过设置响应头,允许跨域请求访问资源。
      3. 但CORS 在浏览器中有兼容性,只支持 XMLHttpRequest Level2 的浏览器,才能正常开启 CORS (例如:IE10+、Chrome4+、FireFox3.5+)。
    2. CORS 跨域资源实现方式
      通过指定响应头 Access-Control-Allow-Origin 字段对应的值来指定允许访问资源的外域 URL。

      // 只允许来自 http://127.0.0.1:5500 的跨域访问资源请求
      res.setHeader('Access-Control-Allow-Origin', 'http://127.0.0.1:5500');
      // 值为 '*' : 表示允许来自任何域的请求
      res.setHeader('Access-Control-Allow-Origin', '*');
      
    3. CORS 默认支持9个请求头

      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 字段对额外的请求进行声明。

      // 允许客户端额外向服务器发送 X-Custom-Header 请求头
      res.setHeader('Access-Control-Allow-Headers', 'X-Custom-Header');
      // 可以同时设置多个请求头,多个请求头之间用英文逗号分隔
      res.setHeader('Access-Control-Allow-Headers','Content-Type,X-Custom-Header');
      
    4. CORS 默认情况下仅支持客户端发起的简单请求(GET、POST、HEAD)。
      如果服务器想要允许客户端通过非简单请求(预检请求)来请求服务端的资源,可以通过 Access-Control-Alow-Methods 字段来设置客户端可以使用的请求方式。

      // 允许客户端使用 GET, POST, HEAD, DELETE 方式请求资源
      res.setHeader('Access-Control-Alow-Methods', 'GET, POST, HEAD, DELETE');
      // 允许客户端使用所有的HTTP请求方式
      res.setHeader('Access-Control-Alow-Methods', '*');
      
    5. 简单请求

      • 请求方式为 GET、POST、HEAD 三者之一。
      • 客户端请求头部无自定义头部字段。
      • 客户端只会向服务端发送一次请求。
    6. 预检请求

      • 请求方式为 GET、POST、HEAD 之外的请求类型。
      • 请求头部包含自定义头部字段。
      • 向服务器发送 application/json 格式的数据。
      • 客户端会向服务器发送两次请求。
        1. 在浏览器与服务器正式通信之前,浏览器会先发送 OPTION 请求进行预检,以获知服务器是否允许该实际请求。
        2. 服务器成功响应OPTION请求(预检请求)后,才会发送真正的请求,并且携带真实数据。

    4.3 跨域解决方案

    1. CORS(主流方案,只需要在后端配置,推荐使用)
    2. JSONP(兼容性好,需要前后端配合,但只支持GET请求)

    4.4 使用 cors 中间件解决跨域问题

    cors 是 express 的一个第三方中间件,通过安装和配置中间件,可以方便解决跨域问题。

    • 安装: npm i cors
    • 导入: const cors = require('cors')
    • 全局配置: app.use(cors())

    4.5 使用 jsonp 解决跨域问题

    • 服务器端代码
      app.get('/api/jsonp', (req, res) => {
         // 1. 得到函数的名称
         const funName = req.query.callback
         // 2. 定义要发送到客户端的数据对象
         const data = { name: 'zs', age: 22 }
         // 3. 拼接出一个函数的调用
         const scriptStr = `${funName}(${JSON.stringify(data)})`
         // 4. 把拼接的字符串,响应给客户端
         res.send(scriptStr)
      })
      
    • 客户端代码
      $.ajax({
         type: 'GET',
         url: 'http://127.0.0.1/api/jsonp',
         dataType: 'jsonp',
         success: function (res) {
            console.log(res);
         }
      })
      

    PS: 如果本文对你有所帮助,请点个赞吧!

  • 相关阅读:
    vue part1 基础
    【转载】NBU异机恢复oracle
    【转载】跨域请求
    [转载] django contenttypes
    rest_framework setting
    rest_framework 视图/路由/渲染器/认证授权/节流
    【转载整理】 mysql百万级数据库分页性能
    rest_framework 分页
    rest_framework 序列化
    django middleware
  • 原文地址:https://www.cnblogs.com/discourage/p/13858080.html
Copyright © 2011-2022 走看看