1. node知识汇总02

82 阅读8分钟

1.7 express

  • 官方给出的概念:Express 是基于 Node.js 平台,快速、开发、极简的 Web 开发框架。通俗易懂的理解:Express 的作用和 Node.js 内置的 http 模块类似,是专门用来创建 Web 服务器
npm i express -S
1.7.1 创建基本的 web 服务器
// 1. 导入 express
const express = require('express');
// 2. 创建 web 服务器
const app = express();

// 3. 调用 app.listen(端口号, 启动成功之后的回调函数),启动服务器
app.listen(80, () => {
	console.log('express server running at http://127.0.0.1');
})
1.7.2 监听请求
  • 监听 GET 请求

    • 通过 app.get() 方法,监听客户端的 GET 请求,具体语法格式如下:
    /**
     * app.get('请求的URL', (req, res) => { 处理函数 })
     * 参数1:请求的URL
     * 参数2:请求所对应的回调函数
     *        req:请求对象(包含了与请求相关的属性和方法)
     *        res:响应对象(包含了与响应相关的属性和方法)
     */
    app.get('/list', (req, res) => {
      const data = {
        "name": "胖丁",
        "age": 22,
      };
      res.send(data);
    });
    
  • 监听 POST 请求

    • 通过 app.post() 方法,监听客户端的 POST请求,具体语法格式如下:
    /**
     * app.post('请求的URL', (req, res) => { 处理函数 })
     * 参数1:请求的URL
     * 参数2:请求所对应的回调函数
     *        req:请求对象(包含了与请求相关的属性和方法)
     *        res:响应对象(包含了与响应相关的属性和方法)
     */
    app.post('/user', (req, res) => { 
      const data = {
        "name": "胖丁",
        "age": 22,
      };
      res.send(data);
    });
    
  • 将内容响应给客户端

    • 通过 res.send()
    // 1、 导入 express
    const express = require('express');
    
    // 2. 创建 web 服务器
    const app = express();
    
    // 4. 监听客户端的 GET 和 POST 请求,并向客户端响应具体的内容
    app.get('/user', (req, res) => {
      // 调用 express 提供的 res.send() 方法,向客户端响应一个 JSON 对象
      res.send({"name": "zs", "age": 22, "gender": "男"});
    });
    
    app.post('/user', (req, res) => {
      // 调用 express 提供的 res.send() 方法,向客户端响应一个 文本字符串
      res.send('请求成功');
    });
    
    // 3. 启动 web 服务器
    app.listen(80, ()=> {
      console.log('express server running at http://127.0.0.1');
    });
    
  • 获取 URL 中携带的查询参数

    • 通过 req.query 对象,可以访问到客户端通过查询字符串的形式,发送到服务器的参数
    app.get('/list', (req, res) => {
      /**
       * req.query 默认是一个空对象
       * 客户端使用 ?name=zs&age=22 这种查询字符串形式,发送到服务器的参数
       */
      console.log(req.query, 'query');
    });
    
    http://127.0.0.1/list?name=芳芳&age=22  // 客户端的请求
    
  • 获取 URL 中的动态参数

    • 通过 req.params 对象,可以访问到 URL 中,通过 : 匹配到的动态参数
    app.get('/home/:id/:name', (req, res) => {
    
      /**
       * req.params 默认是一个空对象, 里面存放着通过 : 动态匹配到的参数值
       * 客户端请求 /1/芳芳
       */
      console.log(req.params);
      res.send(req.params);
    });
    
    http://127.0.0.1/home/1/芳芳
    
  • 托管静态资源

    • 通过 express.static() 我们可以非常方便地创建一个静态资源服务器,例如,通过如下代码就可以将 public 目录下的图片、CSS 文件、JavaScript 文件对外访问
    app.use(express.static('public'));    // 'publice' 文件夹名
    
    • 注意:Express 在指定的静态目录中查找文件,并对外提供资源的访问路径。因此,存放静态文件的目录名不会出现在 URL 中
    http://129.0.0.1/index.js
    http://129.0.0.1/index.css
    http://129.0.0.1/index.html
    http://129.0.0.1/image
    
    • 托管多个静态资源目录
    app.use(express.static('public'));
    app.use(express.static('file'));
    // 访问静态资源文件时,express.static() 函数会根据目录的添加查询所需的文件
    
    • 挂载路径前缀
    app.use('/file', express.static('public'))
    http://129.0.0.1/file/index.js
    http://129.0.0.1/file/index.css
    http://129.0.0.1/file/index.html
    http://129.0.0.1/file/image
    

1.8 路由

1.8.1 路由注册
// 导出路由模块
const router = require('./router');
// 注册路由模块
app.use(router);
// 注:统一给路由添加前缀 /api 就是统一添加的前缀
// app.use('/api', router)
1.8.2 创建路由模块
const express = require('express');    // 1. 导入 express
const router = express.Router();       // 2. 创建路由对象

router.get('/user/list', function(req, res){ // 3. 挂载获取用户列表的路由
	res.send('Get user list');
})
router.post('/user/add', function(req, res){ // 4. 挂载添加用户的路由
	res.send('Add new user');
})
module.exports = router                  // 5. 向外导出路由对象
const express = require('express');
const userRouter = require('./02.user.js');

const app = express();

app.use(userRouter);


app.listen(80, ()=> {
  console.log('express server running at http://127.0.0.1');
});
1.8.3 Express 中间件
  • Express 中间件的调用流程

    • 当一个请求到达 Express 的服务器之后,可以连续调用多个中间件,从而对这次请求进行预处理

    ![](./Image./03 express中间件的调用流程.png)

  • Express 中间件本质上就是一个 function 处理函数,Express 中间件的格式如下:

    const express = require('express');
    const app = express();
    
    app.get('/', (req, res, next) => {
      res.data = {
        name: '胖丁',
        age: 22,
      }
    	next();  // 中间件函数的形参列表中,必须包含 next 函数
        // next 函数是实现多个中间件连续调用的关键,它表示把流转关系转交给下一个中间件或路由
    });
    app.get('/', (req, res) => {
      res.data.hobby = '吃饭',
      res.send(res.data);
    });
    
    app.get('/user', (req, res) => {
      
      res.send(res.data || 'res.data 是空的');
    });
    
    app.listen('80', () => {
    	console.log('express server running at http://127.0.0.1');
    });
    
    • express 中间件 路由 之间的区别:中间件函数的形参列表中,必须包含 next 函数,而路由处理函数中只包含 reqresnext 函数是实现多个中间件连续调用的关键,它表示把流转关系转交给下一个中间件或路由
  • 全局生效的中间件

    • 客户端发起的任何请求,到达服务器之后,都会触发的中间件,叫做全局生效的中间件通过调用 app.use(中间件函数),即可定义一个全局生效的中间件,示码如下:
    const mw = (req, res, next) {
    	console.log('这是一个简单的中间件函数');
    	next();
    };
    // 全局生效的中间件
    app.use(mw)
    
    • 中间件的作用:多个中间件之间,共享同一份 req 和 res 。基于这样的特性,我们可以在上游的中间件中,统一为 req 或 res 对象添加自定义的属性或方法,供下游的中间件或路由进行使用
  • 局部生效的中间件

    • 不使用 app.use() 定义的中间件,叫做局部生效的中间件,示码如下:
    // 定义中间件函数
    const mw = function(req, res, next){
    	console.log('这是中间件函数');
    	next()
    };
    const mw1 = function(req, res, next){
    	console.log('这是中间件函数1');
    	next()
    };
    // 局部中间件的调用
    app.get('/', mw, (req, res) => {
    	res.send('Home page');
    });
    
    // 多个局部中间件的调用
    app.post('/', mw, mw1, (req, res) => {
        res.send('Home page');
    });
    
    app.get('/user', (req, res) => {
    	res.send('User page');
    });
    
    • 定义多个局部中间件
    app.get('/', mw1, mw2, (req, res) => {
    	res.send('Home page');
    });
    app.get('/', [mw1, mw2], () => {
    	res.send('Home page');
    })
    
    • 了解中间件的5个使用注意事项:

      • 一定要在路由之前注册中间件
      • 客户端发送过来的请求,可以连续调用多个中间件进行处理
      • 执行完中间件的业务代码之后,不要忘记调用 next() 函数
      • 为了防止代码逻辑混乱,调用 next () 函数后不要再写额外的代码
      • 连续调用多个中间件时,多个中间件之间,共享 req 和 res 对象
    • 中间件的分类

      • 应用级别的中间件

      • 路由级别的中间件

      • 错误级别的中间件

        • 错误级别的中间件的作用:专门用来捕获整个项目中发生的异常错误,从而防止项目异常崩溃的问题
        • 注意:错误级别的中间件,必须注册在所有路由之后,在路由执行之后发生抛出错误会跳出往后查找错误级别的中间件
        app.get('/', function(req, res) => {
        	throw new Error('服务器内部发生了错误'); // 抛出一个错误
        	res.send('Home page');
        });
        app.use((err, req, res, next) => { // 错误级别的中间件
        	console.log('发生了错误:' + err.message); // 在服务器打印错误的消息
        	res.send('Error:' + err.message); // 想客户端相应错误的相关的内容
        })
        
    • 自定义中间件

      • 监听 req 的 data 事件

        • 监听 req 的 data 事件,来获取客户端发送到服务器的数据
      • 监听 req 的 end 事件

      • 监听 querystring 模块解析请求体数据

        • Node,js 内置了一个 querystring 模块,专门用来处理查询字符串,通过这个模块提供的 parse() 函数,可以轻松把查询字符串,解析成对象的格式
        const qs = require('querystring');
        
        const body = qs.parse(str);
        
      • 将解析出来的数据对象挂载为 res.body

      • 将自定义中间件封装为模块

      const express = require('express');
      
      // 导入 node.js 内置的 querystring 模块
      const qs = require('querystring');
      
      const app = express();
      
      app.use((req, res, next) => {
      	// 定义中间件具体的业务逻辑
      	let str = '';
      	// 监听 req 的 data 事件
      	req.on('data', (chunk) => {
      		// 拼接请求体数据,隐式转换为字符串
      		str += chunk
      	});
      	// 监听 req 的 end 事件
      	req.on('end', () => {
      		const body = qs.parse(str);
      		req.body = body;
      		next()
      	})
      });
      

1.9 CORS 跨域资源共享

// 运行 npm install cors 安装中间件
npm i cors
// 使用 const cors = require('cors') 导入中间件
const cors = require('cors') 
// 在路由之前调用 app.use(cors()) 配置中间件
app.use(cors())
/**
 * 使用 CORS 中间件解决跨域问题
 * 运行 npm install cors 安装中间件
 * 使用 const cors = require('cors') 导入中间件
 * 在路由之前调用 app.use(cors()) 配置中间件
 */

// CORS 响应头部 Access-Control-Allow-[Origin]
/** 
 * Access-Control-Allow-Origin: <origin> | *
 * origin 参数的值指定了允许访问该资源的外域 URL
 * 例如:res.setHeader('Access-Control-Allow-Origin', 'http://itcast.cn) 表示只能让传智播客的网页访问
 * '*' 表示跨域让任何域的网站访问
 * 
 * Access-Control-Allow-Headers
 * 默认情况下,CORS 仅支持客户端想服务器发送 9 个请求头
 * 如果客户端想向服务器发送额外的请求头信息,则需要服务器,通过 Access-Control-Allow-Headers 对额外的请求头进行声明
 * res.setHeader('Access-Control-Allow-Headers', 'Content-Type, X-Custom-Header')
 * 
 * Access-Control-Allow-Methods
 * 默认情况下,CORS 仅支持客户端发起的 GET POST HEAD 请求
 * 如果客户端希望通过 PUT DELETE 等方式请求服务器的资源,则需要在服务器,通过 Access-Content-Allow-Methods 来指明实际请求所允许使用的 HTTP 方法
 * 只允许 POST GET DELETE HEAD 请求方法 res.setHeader('Access-Control-Allow-Methods', 'POST, GET, DELETE, HEAD')
 * 允许所有的 HTTP 请求方法 res.setHeader('Access-Control-Allow-Methods', '*')
 **/ 

1.10 编写 jsonp 接口

app.get('/api/jsonp', (req, res) => {
  console.log('111');
  // 1. 获取客户端发送过来的回调函数的名字
  const funcName = req.query.callback;
  // 2. 得到要通过 JSONP 形式发送给客户端的数据
  const data = {
    name: '胖丁',
    age: 22,
  };
  // 3. 根据前两步得到的数据,拼接出一个函数调用的字符串
  const scriptStr = `${funcName}(${JSON.stringify(data)})`;
  // 4. 把上一步拼接得到的字符串,响应给客户端
  res.send(scriptStr)
});
  • HTML 部分
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
  <script src="https://cdn.staticfile.org/jquery/1.10.0/jquery.min.js"></script>
<body>
    <button id="btnGET">GET</button>
    <button id="btnPOST">POST</button>
    <button id="btnJSONP">JSONP</button>
</body>
<script>
  $('#btnPOST').on('click', () => {
    $.ajax({
      type: 'POST',
      url: 'http://127.0.0.1/api/post',
      data: {
        name: '胖丁',
        age: '26'
      },
      success: (res) => {
        console.log(res);
      }
    })
  })
  $('#btnGET').on('click', () => {
    $.ajax({
      type: 'get',
      url: 'http://127.0.0.1/api/get',
      data: {
        name: '芳芳',
        age: '21'
      },
      success: (res) => {
        console.log(res);
      }
    }) 
})
$('#btnJSONP').on('click', () => {
  console.log('我被调用了');
    $.ajax({
      type: 'get',
      url: 'http://127.0.0.1/api/jsonp',
      dataType: 'jsonp',
      // data: {
      //   name: '胖丁',
      //   age: '26'
      // },
      success: (res) => {
        console.log( 'res', res);
      }
    })
  })
</script>
</html>

Node 开发好用的插件

  • nodemon 能够监听项目文件的变动,当代码被修改后,nodemon 会自动帮我们重启项目,极大方便了开发和调试

    npm i nodemon -g