Node第二弹:Node服务端应用路由解析

大家好,我是山月。在上篇文章介绍了 HTTP 报文及简单的服务端框架要素,如如何接受请求参数等。这篇文章介绍另一个常见的主题:路由。

让客户满意是我们工作的目标,不断超越客户的期望值来自于我们对这个行业的热爱。我们立志把好的技术通过有效、简单的方式提供给客户,将通过不懈努力成为客户在信息化领域值得信任、有价值的长期合作伙伴,公司提供的服务项目有:域名与空间、网页空间、营销软件、网站建设、上高网站维护、网站推广。

简单路由

最简单的路由可使用 req.url 进行路由分发不同的逻辑,代码如下所示。

但是对于一个非Demo式的页面,业务逻辑都堆在一起,这显得太为简陋。

 
 
 
 
  1. const http = require('http')
  2. const server = http.createServer((req, res) => {
  3.   console.log(req.url)
  4.   let data = ''
  5.   if (req.url === '/') {
  6.     data = 'hello, world'
  7.     res.end(data)
  8.   } else if (req.url === '/json') {
  9.     res.setHeader('Content-Type', 'application/json; charset=utf-8');
  10.     data = JSON.stringify({ username: '山月' })
  11.     res.end(data)
  12.   } else if (req.url === '/input') {
  13.     let body = ''
  14.     req.on('data', chunk => body += chunk)
  15.     req.on('end', () => {
  16.       data = body
  17.       res.end(data)
  18.     })
  19.   }
  20.   
  21. })
  22. server.listen(3000)

复杂路由

作为一个能够在生产环境使用,较为复杂的路由至少能够解析以下路由,并为单独路由配置单独的业务逻辑处理函数

 
 
 
 
  1. Method: app.post('/', handler)
  2. Param Path: app.post('/users/:userId', handler)

基于正则路由

目前,绝大部分服务端框架的路由都是基于正则进行匹配,如 koa、express 等。另外,前端框架的路由 vue-router 与 react-router 也是基于正则匹配。

而这些框架基于正则匹配的路由,都离不开一个库: path-to-regexp,它将把一个路由如 /user/:name 转化为正则表达式。

https://github.com/pillarjs/path-to-regexp

标题:path-to-regexp

它的 API 十分简单:

  • pathToRegexp: 可将路由转化为正则表达式
  • match: 可匹配参数
 
 
 
 
  1. const { pathToRegexp, match, parse, compile } = require('path-to-regexp')
  2. pathToRegexp('/api/users/:userId')
  3. //=> /^\/api\/users(?:\/([^\/#\?]+?))[\/#\?]?$/i
  4. const toParams = match('/api/users/:userId')
  5. toParams('/api/users/10')
  6. //=> {
  7. //   index: 0
  8. //   params: {userId: "12"}
  9. //   path: "/api/users/12"
  10. // }

那这些 Node 服务器框架基于正则路由的原理是什么?

  • 注册路由。每一个路由都作为一个 Layer (在 express、koa 中),并使用 path-to-regexp 把路由路径转化为正则,作为 Layer 的属性。
  • 匹配路由。当一次请求来临时,对比路由表中每一条路由,找到匹配正则的多条路由,执行多条路由所对应的业务处理逻辑。

从上可以看出它没进行一次路由匹配的时间复杂度为: 「O(n) X 正则匹配复杂度」

基于正则路由的一些问题

性能问题先不谈,先看一个问题:

「当我们请求 /api/users/10086,有两条路由可供选择: /api/users/10086 与 /api/users/:userId,此时将会匹配哪一条路由?」

以下是由 koa/koa-router 书写, 「由于是正则匹配,此时极易出现路由冲突问题,匹配路由时与顺序极为相关。」

 
 
 
 
  1. const Koa = require("koa");
  2. const Router = require("@koa/router");
  3. const app = new Koa();
  4. const router = new Router();
  5. router.get("/api/users/10086", (ctx, next) => {
  6.   console.log(ctx.router);
  7.   ctx.body = {
  8.     userId: 10086,
  9.     direct: true
  10.   };
  11. });
  12. router.get("/api/users/:userId", (ctx, next) => {
  13.   console.log(ctx.router);
  14.   ctx.body = {
  15.     userId: ctx.params.userId
  16.   };
  17. });

基于前缀树路由 (Trie、Radix Tree、Prefix Tree)

相对于正则匹配路由而言,基于前缀树匹配更加高效,且无上述路由冲突问题。

  • find-my-way

https://github.com/delvedor/find-my-way

标题:find-my-way

 
 
 
 
  1. const http = require('http')
  2. const router = require('find-my-way')()
  3. const server = http.createServer((req, res) => {
  4.   router.lookup(req, res)
  5. })
  6. router.on('GET', '/api', () => {})
  7. router.on('GET', '/api/users/:id', (req, res) => { res.end('id') })
  8. router.on('GET', '/api/users/10086', (req, res) => { res.end('10086') })
  9. router.on('GET', '/api/users-friends', () => {})
  10. console.log(router.prettyPrint())
  11. server.listen(3000)

在上述代码中,将把所有路由路径构成前缀树。前缀树,顾名思义,将会把字符串的公共前缀提取出来。

 
 
 
 
  1. └── /api (GET)
  2.     └── /users
  3.         ├── /
  4.         │   ├── 10086 (GET)
  5.         │   └── :id (GET)
  6.         └── -friends (GET)

可以看出,前缀树路由的匹配时间复杂度明显小于 O(n),且每次不会有正则路由进行正则匹配的复杂度。这决定了它相比正则路由更高的性能。

Node 中最快的框架 fastify,便是内置了基于前缀树的路由。

 
 
 
 
  1. const fastify = require('fastify')()
  2. fastify.get('/api/users/10086', async (request, reply) => {
  3.   return { userId: 10086, direct: true }
  4. })
  5. fastify.get('/api/users/:id', async (request, reply) => {
  6.   const id = request.params.id
  7.   return { userId: id }
  8. })
  9. fastify.listen(3000)

405

在 HTTP 状态码中,与路由相关的状态码为 404、405,作为一个专业的路由库,实现一个 405 也是分内之事。

  • 301
  • 302
  • 307
  • 308
  • 404: Not Found
  • 405: Method Not Allowed

嗯,代码就不放了... 本文转载自微信公众号「全栈成长之路」,可以通过以下二维码关注。转载本文请联系全栈成长之路公众号。

本文名称:Node第二弹:Node服务端应用路由解析
转载来于:http://www.csdahua.cn/qtweb/news29/536879.html

网站建设、网络推广公司-快上网,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等

广告

声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 快上网