首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

Golang实例:从零构建一个HTTP路由器

HTTP路由器(也称为multiplexer)负责侦听HTTP请求并根据匹配条件(例如HTTP方法或URL)调用适当的处理程序。

Golang提供了一个非常简单的路由器ServeMux。但它太基础简单,所以大家一般都会选择第三方路由模块,比如gorilla/mux。

今天我们来学习下如何从零自己构建一个HTTP路由。

概述

一个HTTP路由器主要负责以下几件事:

404处理程序:为不匹配的请求提供404响应

匹配:匹配URL路径和HTTP方法并调用路由处理程序

参数:提取动态网址参数,例如/users/(?P\d+)

紧急恢复:赶上紧急情况并回复500

下面是一个代码片段,展示了上述的所有功能:

基本路由

首先,我们构建一个路由,该路由负责响应无效请求,并返回404响应。

路由器处理进入Web服务器的每个HTTP请求,可以通过将其传递到Golang的http.ListenAndServe方法中来完成。ListenAndServe的第二个参数是http.Handler,它负责处理每个传入的请求。为了实现这一点,我们的路由器将需要实现该Handler接口。

Handler只声明一个方法,ServeHTTP所以我们创建一个结构来匹配它。

这样就有一种可以在任何http.Handler接受的地方使用的路由类型。把加入到可运行的程序中httper.go。

从命令行运行该程序go run httper.go,然后就可以通过Web浏览器中打开127.0.0.1:8000,验证其是否响应"404页面未找到"。

路由匹配

一个总是返回404请求的路由并什么太多用处。我们继续修改路由以便可以匹配的列表。

对于每个传入请求,需要执行以下操作:

从请求中提取HTTP方法和URL路径;

检查是否存在与方法和路径匹配的路由;

匹配时调用它;

如果找不到匹配项,则返回404。

为此,为每条路由需要保存这些信息:路由的HTTP方法,路由的路径以及如果找到匹配项,则调用的处理函数。我们创建一个结构RouteEntry来将存储在他们。

还需要更新Router以存储的列表RouteEntry。为了改善使用路由的体验,我们添加一个名为helper的辅助功能Route来完成这项工作。路由功能将创建一个新路由RouteEntry并将其添加到路由列表中。

最后,编写逻辑以检查传入的请求并找到匹配的路由。

匹配逻辑有两个明显的地方:Router本身还是RouteEntry。这些位置中的任何一个都可以使用,但是使用RouteEntry匹配负责是明智的,因为它存储了要匹配的条件。

我们给RouteEntry结构添加一个Match方法。由于基于请求的信息进行匹配,因此将request作为参数。为了表明匹配成功,将让它返回一个布尔值。

现在,路由器所需要做的就是遍历所有路由,并检查其中是否有匹配请求。

为了确保所有操作都能正常进行,新添加一条简单的路由来处理。

当加入这些代码,然后go run httper.go。可以通过浏览器访问127.0.0.1:8000/来验证其是否有效。应该看到它以"Hello,Chongchong!"回应。任何其路径会返回404响应。

提取路由参数

现在,有了一个基本实用的HTTP路由器。我们进一步添加功能充实它。常用的系统处理API中都会涉及增删改查(CRUD)的动态参数的定义的路由。例如,URL通过ID获取用户的路由,可能的路径为/users/10 ,其中10为用户ID。在当前的路由器中,如果一个一个的为每个可能的用户ID都定义一个路由显然是冗杂和不必要的。实际上需要的是一种定义带有动态路径的方法/users/?。

为了执行动态匹配,需要使用利器——正则表达式。

访问参数

不过,在深入探讨正则表达式之前,先讨论一下路由处理程序将如何访问提取的参数。一个fetchUserRoute将需要能够从URL中提取ID来获取正确的用户。

幸运的是,Golang提供了一种机制,可以将短暂的数据存储在称为context的请求对象上。用这种机制,路由器可以将参数添加到请求上下文中,以供处理程序在调用时读取。

下面是处理程序如何访问参数的示例。注意,由于访问请求上下文中的内容有点麻烦,因此又创建一个了辅助函数来减少重复。

用正则匹配

将把参数存储在中map[string]string,其中映射中的每个键都是参数名称,而值是从URL中提取的值。正则表达式已命名了适合此用例的组。在Golang中,可以使用FindStringSubmatch方法匹配这些命名组。

保存网址参数

知道如何匹配正则表达式组,我们将可以更新RouteEntry结构的匹配逻辑以使用它们。为此,需要将Path属性从字符串更改为Regexp类型。然后,需要更新Match方法逻辑。

注意,上面还更改了的签名Match以返回参数映射,而非布尔值。

最后需要做的一件事是更新路由器逻辑,以在找到匹配项后将参数添加到请求上下文中。

我们在程序中添加这些部分,然后测试:

Panic恢复

添加动态URL参数极大地提高了路由器的实用性。现在可以将其在一些项目中使用。为了防止生产中发生坏事,应该增加另外一件事,那就是紧急恢复。

当前,如果路由处理程序之一出现紧急情况,服务器将返回一个空响应,而不是默认页面。将添加以下几行代码来捕获这些紧急情况并返回适当的500(内部服务器错误)状态代码。

为了测试它是否有效,我们添加一条特殊的/panic路由来触发该恢复逻辑。

测试访问 127.0.0.1:8000/panic,就会返回 Uh oh!

总结

本我们实例介绍了如何使用Golang语言的标准库,从头开始构建一个路由器,当然我们构建的路由器仅仅为HTTP路由原理说明、练手和好玩,不建议在生产环境使用!在生产中使用建议使用成熟的类库,比如gorilla/mux。

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20200928A0DS4600?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券