Bootstrap

node.js路由


1、node.js路由

1. 什么是路由

  1. 在Web开发中,路由是一个重要的概念。它用于将URL映射到相应的处理程序或控制器,以便处理客户端的请求。
  2. 在 Node.js 中,路由是处理 HTTP 请求的关键部分,它决定了如何根据不同的 URL 和 HTTP 方法(如 GET、POST、PUT、DELETE 等)来分发请求。
  3. 路由通常用于构建 Web 应用程序,特别是 RESTful API。
  4. Node.js 本身并没有内置的路由机制,可以通过中间件库(如 Express)来实现。

路由通常涉及以下几个方面:

  • URL 匹配:根据请求的 URL 来匹配路由规则。
  • HTTP 方法匹配:根据请求的 HTTP 方法(GET、POST、PUT、DELETE 等)来匹配路由规则。
  • 请求处理:一旦匹配到合适的路由规则,就调用相应的处理函数来处理请求。

2. node.js路由的工作原理

node.js路由的工作原理可以分为以下步骤

  1. 请求处理:当服务器接收到一个请求时,它会解析请求的 URL 和 HTTP 方法。
  2. 路由匹配:服务器会根据请求的 URL 和 HTTP 方法,在路由表中查找匹配的路由。
  3. 执行处理函数:找到匹配的路由后,服务器会执行与该路由关联的处理函数。
  4. 发送响应:处理函数执行完毕后,服务器会向客户端发送响应。

2、在node.js中,内置模块实现路由

1.案例

在Node.js中,可以使用内置的http模块来创建简单的服务器,并且处理路由。

const http = require('http');
const port = 3001
// 创建服务器并定义路由
const server = http.createServer((req, res) => {
  const { url, method } = req;
  res.statusCode = 200
    res.setHead({ 'Content-Type': 'text/plain' });
    res.end('Home Page');
});

server.listen(port, () => {
  console.log('Server is running on http://localhost:' + port);
});

在这里插入图片描述

2.createServer()

createServer() 用于创建一个 Web 服务器
访问 Node.js 的 GitHub 仓库:https://github.com/nodejs/node

  1. 源码存于lib/http.js文件中,内部就一行代码,实例化一个 Server 类,如下图。
    在这里插入图片描述
  2. Server 类的实现存于lib/_http_server.js文件中,由源码可知,http.Server 继承自 net.Server,而 net 模块可创建基于流的 TCP 和 IPC 服务器。
  3. http.createServer() 在实例化 net.Server 的过程中,会监听 request 和 connection 两个事件。

3.end()

很多时候写入流是不需要手动调用 end() 方法来关闭的。但如果在读取期间发生错误,那就不能关闭写入流,发生内存泄漏。
 为了防止这种情况发生,可监听可读流的错误事件,手动关闭,如下所示。

	readable.on('error', function(err) {
	  writeable.close();
	});

接下来看一种网络场景,改造一下之前的示例,让可读流监听 data、end 和 error 事件,当读取完毕或出现错误时关闭可写流。

const http = require('http');
const port = 3001
var fs = require("fs");
http.createServer((req, res) => {
	// 创建一个可读流
  const readable = fs.createReadStream(__dirname + '/data.txt')
  // 处理流事件 --> data, end, and error
  // data    当有数据可读时触发。
  // end    没有更多的数据可读时触发。
  // error   在接收和写入过程中发生错误时触发。
  // finish  所有数据已被写入到底层系统时触发。
  readable.on('data', chunk => {
    console.log(chunk)
    res.write(chunk);
  });
  readable.on('end',() => {
    res.end('File END');
  })
  readable.on('error', err => {
    console.log(err)
    res.end('File not found');
  });
  readable.on('finish', err => {
    res.end('File finish');
  });
}).listen(port, () => {
  console.log('Server is running on http://localhost:' + port);
})

在这里插入图片描述
 若不手动关闭,页面将一直处于加载中,在KOA源码中,多处调用了此方法。
 注意,若取消对 data 事件的监听,那么页面也会一直处于加载中,因为流一开始是静止的,只有在注册 data 事件后才会开始活动。

4.listen()

listen() 方法用于监听端口,它就是 net.Server 中的 server.listen() 方法。

ObjectSetPrototypeOf(Server.prototype, net.Server.prototype);

5.req 和 res

实例化 Server 时的 requestListener() 回调函数中有两个参数 req(请求对象) 和 res(响应对象)。

  1. 通过 TCP 协议传输过来的二进制数据,会被 http_parser 模块解析成符合 HTTP 协议的报文格式。
  2. 在将请求首部解析完毕后,会触发一个 parserOnHeadersComplete() 回调函数,在回调中会创建http.IncomingMessage 实例,也就是 req 参数。
  3. 而在这个回调的最后,会调用 parser.onIncoming() 方法,在这个方法中会创建 http.ServerResponse 实例,也就是 res 参数。
  4. 最后会触发在实例化 Server 时注册的 request 事件,并将 req 和 res 两个参数传递到 requestListener() 回调函数中。

3、请求参数

  1. 路径解析
    可以使用 URL 对象和 querystring 模块,解析参数。
    用URL对象解析参数在node全局对象一文中有介绍
  • querystring 模块
    querystring 模块用于处理 URL 查询字符串和 POST 请求的数据。
    • querystring.parse()方法解析字符串为一个对象。
      	const querystring = require('querystring');
      	const str = 'foo=bar&abc=xyz&abc=123';
      	const obj = querystring.parse(str);
      	console.log(obj);   // { foo: 'bar', abc: [ 'xyz', '123' ] }
      
    • querystring.stringify() 方法序列化一个对象为一个字符串。
      	const querystring = require('querystring');
      	const obj = { foo: 'bar', abc: [ 'xyz', '123' ] };
      	const str = querystring.stringify(obj);
      	console.log(str); // foo=bar&abc=xyz&abc=123
      
    • querystring.escape() 和 querystring.unescape() 方法来对和解码URL组件。
      const querystring = require('querystring');
      const str = 'Hello World!';
      const escapedStr = querystring.escape(str);
      console.log(escapedStr); // Hello%20World!
      const unescapedStr = querystring.unescape(escapedStr);
      console.log(unescapedStr); // Hello World!
      
  • server.js封装
    server.js文件定义了服务器的启动逻辑,并在接收到请求时调用路由函数。
    const http = require('http');
    var { URL } = require("url");
    const port = 3001
    // 创建服务器并定义路由
    function server(route) {
      const server = http.createServer((req, res) => {
        const { url, method } = req;
        const pathname = new URL(req.url, `http://${req.headers.host}`).pathname
        route(pathname, method); 
        // 设置响应头和响应内容
        res.writeHead(200, { 'Content-Type': 'text/plain' });
        res.write('Start1 Page'); // 向客户端发送响应内容
        res.end();
      });
      
      server.listen(port, () => {
        console.log('Server is running on http://localhost:' + port);
      });
    }
    module.exports.server = server;
    
  • router.js文件
    router.js 处理路由逻辑,定义并导出 route 函数,用于在服务器收到请求时处理不同路径
    function route(pathname, method) {
      console.log("pathname:" + pathname, '请求方式:' + method);
    }
    // 导出了 route 函数
    exports.route = route;
    
  • index.js文件
    index.js 是程序的入口文件,负责启动服务器并将路由模块传入服务器模块中。
    现在启动应用(node ./index.js,始终记得这个命令行),随后请求一个URL,会看到应用输出相应的信息,表明 HTTP 服务器已经在使用路由模块了,并会将请求的路径传递给路由:
    var server = require("./server");
    var router = require("./router");
     console.log(router.route)
    server.server(router.route);
    
    在这里插入图片描述
;