Go 框架三件套详解(Web/RPC/ORM) | 青训营笔记

262 阅读9分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第3天

现代Web技术大多基于HTTP协议构建,所谓Web框架技术,其本质是在框架底层对HTTP进行有设计的再度封装,最基本的为对Request和对Response处理的封装,除此也包括路由调度,请求参数校验,模板引擎等。再附加一些加速开发和模块管理的套件,如:中间件、MVC分层设计、数据库IO处理等开发套件。使用框架的目的在于屏蔽一些通用的底层编码,封装对用户友好的调用方法,让你把精力集中在业务模块的开发。当然这种封装有利有弊。利在于你不用重复造轮子,有专业的框架团队帮你维护比较规范和安全的底层逻辑,因为框架规范,团队开发中也比较易于沟通;弊在于框架的通用设计有可能不适合你的产品特性,且如果你不深入研究框架底层实现,有可能在项目开发过程中出现一些不可控的bug,这意味着如果你使用一种框架,团队中必须有深入理解该框架的成员,才能让项目开发的进展在可控的范围内。

  1. 框架类型: 开源社区有许许多多不同类型的web框架,帮助用户实现快速上手开发,根据不同的项目需求,你可能需要构建API,有可能构建web页面服务,也有可能构建分布式的微服务,这就区分出许多框架类型,以下为框架类型的划分及热度较高的开源项目:

Router型框架

Ace: 快速开发的Web框架。

api2go: Go的JSON API实现。

Gin: 一个微框架,类似Martinier的API,重点是小巧、易用、性能好很多,也因为 httprouter 的性能提高了40倍。

Goat: Go中的简约REST API服务器

goMiddlewareChain: 一个像express.js的中间件调用链框架。

Hikaru: 支持独立部署和谷歌AppEngine

Hitch: 将 httprouter, httpcontext, 和中间件 捆绑在一起。

httpway: 具有httprouter上下文的简单中间件扩展和具有正常关闭支持的服务框架

kami: 使用 x/net/context的小型Web框架。

Medeina: 灵感来自Ruby的 Roda 和Cuba。

Neko: 一个轻量级Web应用程序框架。

River: 一个简单轻巧的REST服务框架。

Roxanna:httprouter的合并,更好的日志记录和热重载。

siesta:具有上下文的可组合HTTP处理程序。

xmux: xmux is a httprouter fork on top of xhandler (net/context aware) aware)

基于httpRouter进行简单的封装,然后提供定制的中间件和一些简单的小工具集成比如gin,主打轻量,易学,高性能。

迁移型框架

Beego:一个快速开发 Go 应用的 HTTP 框架,他可以用来快速开发 API、Web 及后端服务等各种应用,是一个 RESTful 的框架,主要设计灵感来源于 tornado、sinatra 和 flask 这三个框架,但是结合了 Go 本身的一些特性(interface、struct 嵌入等)而设计的一个框架。beego 是基于八大独立的模块构建的,是一个高度解耦的框架。设计之初就考虑功能模块化,用户即使不使用 beego 的 HTTP 逻辑,也依旧可以使用这些独立模块。

Iris:Iris的理念是为HTTP提供强大的工具,使其成为单页面应用程序,网站,混合或公共HTTP API的理想解决方案。

借鉴其它语言的编程风格,使用MVC开发模式的框架,例如beego、Iris-go等,这种框架方便从其它语言迁移过来的程序员快速上手,快速开发,很多PHP、JAVA程序员对这种框架更容易上手。

代码生成型框架

Goa:Goa采用不同的方法来构建服务,使用简单的Go DSL 来描述服务API 的设计。Goa使用描述生成专门的服务帮助程序代码,客户端代码和文档。Goa可以通过插件扩展,例如 goakit插件生成利用Go套件库的代码。 使用GO DSL描述来生成服务或API代码,支持数据库schema设计,插件设计,大部分代码可直接生成。goa就是这种类型的框架,它着重于构建微服务和API的系统。如果你玩过Yii2或Laravel,你会感觉这种框架开发的套路很熟悉。

微服务型框架

Goa:以上。

go-micro:Go Micro提供了分布式系统开发的核心要求,包括RPC、事件驱动的异步通信、消息编解码、基于服务发现的负载均衡以及可插拔的插件机制。

go-kit:Go kit是一个编程工具包,用于在Go中构建微服务(或优雅的整体)。解决了分布式系统和应用程序架构中的常见问题,因此你可以专注于开发业务。

微服务架构在近年来越来越盛行,在容器化服务的时代,微服务化的应用也代表着未来,go在微服务的开发方面也有得天独厚的优势,这类框架有go-micro、go-kit等,其中go-micro更像是构建微服务的框架,而go-kit更像是微服务开发的工具集。

  1. 框架设计解析 Go在2009年才诞生,迄今也就十年历史,在框架技术方面很多都是借鉴于其他语言的框架设计经验,所以在很多使用框架开发的项目中beego很流行,主要是因为人们更熟悉MVC这种开发套路,但如果你使用beego开发过你会发现有些许别扭,相较于MVC的框架,许多Gopher更喜欢使用轻量级的Router型框架构建REST API,或使用微服务框架搭建运行于容器的应用。或许它更符合Go Web开发的设计理念。至于如何选择框架,这得考虑产品的特性和团队的成员技术栈了,没有唯一答案,适合的才是最好的。

下面我们来解析一下大多数框架设计的共同特性吧:

HTTP封装

Web系统的本质就是对网络通信协议的应用设计,大体上基于HTTP协议进行应用的封装,如许多RESTful风格的API框架,就是完全贴合HTTP协议而设计的。HTTP的一次交互可抽象为Request(请求)和Response(响应),在上一篇中我们了解了Request和Response的具体结构和信息,Request包含八种请求Method来表明客户对资源的操作方式,并赋予请求头、请求参数等信息(在此抽象概述先忽略其它请求报文的处理),而Response则包含服务端在接收到用户请求并进行业务处理后的响应信息,如响应头、状态码、响应体等(在此抽象概述先忽略其他响应报文内容)。这是Web服务端和客户端交互的简单抽象。go的标准库net/http包已实现这些基本的处理,大多web框架根据各自设计的特性进行Request和Response的深度封装,使其对用户开发更友好,或增强其他处理的特性等。

一般框架会对Request和Response进行接口设计或直接设计为结构体实现,在服务中的Handler处理器进行传递,这是net/http包原生的处理方法,但多数框架会把Request和Response以及其他的附加结构封装到一个统一的Context接口或结构体,在服务中的Handler处理器进行传递,如gin

像你以上看到的,许多应用框架会把一次HTTP的交互中的所有要素统一抽象到一个上下文Context中,由路由调度指派的Handler处理器接收处理,于是你会看到gin框架的做法,也为多数web框架的做法

路由设计

在Web交互中,客户端都是通过URL(统一资源定位符)对服务端资源进行HTTP 请求的,一个URL包含资源的请求路径,该路径应由系统路由(router)调度到请求处理器。在常见的Web框架中,router是必备的组件。Go语言圈子里router也时常被称为http的multiplexer。

net/http包内置的ServeMux来完成简单的路由功能,如果开发Web系统对路径中没有带参数要求的话,用net/http标准库中的mux就可以了,但现实并没那么简单,一个稍微复杂的项目都有路径划分及携带参数的要求,特别是RESTful风格的API设计,这就需要对请求路径的URL进行路由调度设计。

在RESTful中除了GET和POST之外,还使用了HTTP协议定义的几种其它的标准化语义。

来看看RESTful中常见的请求路径:

这是常见的几个RESTful API设计。RESTful风格的API重度依赖请求路径。会将很多参数放在请求URI中。除此之外还会使用很多并不那么常见的HTTP状态码。

如果我们的系统也想要这样的URI设计,使用http包的ServeMux显然不够。

较流行的开源go Web框架大多使用httprouter,或是基于httprouter的变种对路由进行支持。前面提到的github的参数式路由在httprouter中都是可以支持的。

因为httprouter中使用的是显式匹配,所以在设计路由的时候需要规避一些会导致路由冲突的情况

简单来讲的话,如果两个路由拥有一致的http方法(指 GET/POST/PUT/DELETE)和请求路径前缀,且在某个位置出现了A路由是wildcard(指:id这种形式)参数,B路由则是普通字符串,那么就会发生路由冲突。路由冲突会在初始化阶段直接panic。

除了正常情况下的路由支持,httprouter也支持对一些特殊情况下的回调函数进行定制,例如404的时候。