goa Runtime 运行时
goa Runtime 在 goa package 中做了实现,包括 HTTP request state
和 response
行为管理、基本数据结构和算法的实现、日志记录、错误处理和支持版本控制等功能。
Goa 行为上下文管理(action context)
Goa 通过实现一个数据结构,并存在于所有的 Goa controller 实现(以第一个参数传参的方式),来实现行为的上下文管理。该方法是参考 google 实现的接口间信息传递的方法,同时根据 Goa 自身情况做了修改。
与其他 Go 实现的 web 框架类似,Goa 的 REST 资源(行为上下文)会开放接口供外部访问。像路径参数、查询结果这样的 API 可以直接通过 GET
方法来获取返回值。在此基础上 Goa 更进一步,用户通过 goagen
工具生成的代码中,根据 design 中指定的参数 type
进行强制准入检验。比如,我们在 design 时定义一个类型为 Integer
的 ID
,则 goagen 生成的 ID
字段中也会定义为 int
,并对该资源的访问进行健壮性检验(比如对 ID 赋值 string
时会返回错误),防止在 server 内部将收到的值赋值给结构体时发生错误。
同样,在 writing response
阶段,Goa 根据设计时的 media type 需求,对返回值进行写入操作。
之前讲到,每个 controller 的 Action 全过程都有一个 action context 管理,因此在开发过程中,每个 Action 的实现都包含 deadline
和 cancelation
信号管理。同时 Goa 内嵌 Timeout
中间件,可以为所有 request 定义 timeout 值。
Goa 功能支持
Server Mux
Goa 通过实现 ServeMux
接口来管理请求的路由,该接口包含一个 Handle
方法,可以将 HTTP 请求的 method 和 url 路径交付给指定 HandleFunc
,通过此函数进行信息处理和反馈。 HandleFunc
作为 Handle
method 的最后一个参数,基本不需要人为修改,其作用主要是为 goagen 生成的代码服务。
This function is intended for the controller generated code. User code should not need to call it directly.
另外, ServeMux
接口有个 version
方法,可以通过其进行版本控制。对不同版本的 HTTP 请求做对应版本的路由处理。该功能通过函数 SelectVersionFunc
实现,实现代码为:
// PathSelectVersionFunc returns a SelectVersionFunc that uses the given path pattern to extract the
// version from the request path. Use the same path pattern given in the DSL to define the API base
// path, e.g. "/api/:version".
// If the pattern matches zeroVersion then the empty version is returned (i.e. the unversioned
// controller handles the request).
func PathSelectVersionFunc(pattern, zeroVersion string) SelectVersionFunc {
rgs := design.WildcardRegex.ReplaceAllLiteralString(pattern, `/([^/]+)`)
rg := regexp.MustCompile("^" + rgs)
return func(req *http.Request) (version string) {
match := rg.FindStringSubmatch(req.URL.Path)
if len(match) > 1 && match[1] != zeroVersion {
version = match[1]
}
return
}
同时 Goa 也提供其他访问方式的 version 路由管理。包括 PathSelectVersionFunc
、 HeaderSelectVersionFunc
和 QuerySelectVersionFunc
。
日志、错误处理及服务退出
日志存在于 Goa
server 的整个运行时,同时包含通信过程中的全部信息: server name
、 controller name
、 action name
和一个全局唯一的 request ID
。
所有 Goa 的 Action 均会返回一个类型为 error 的变量,当此 error 变量不是 nil 时,定义的 controller error handler 会自动调用。默认情况下发生访问错误时会返回一个 500 ERROR 和具体的报错信息。
Goa server 通过 NewGraceful
方式,在保证所有已发送的请求全部处理过后,再进行终止服务。
定制开发
Error Handling
Goa 可以通过 SetHandler
方法来重写默认的 service 错误处理。同时 Goa 也提供两个内嵌 error handlers:
DefaultErrorHandler
:当发生BadRequestError
接口类 error 时返回 400,否则返回 500,并 response body 中记录错误日志。TerseErrorHandler
:返回错误的逻辑与DefaultErrorHandler
相同,只不过该 Handler 不会将内部(internal)错误写入 response body 中。
路由规则和 API 版本控制
正如之前所讲,Goa 支持 API 路由到不同的版本中,该功能可以在设计阶段通过 Version
字段进行指定:
e.g.:
package design
import (
. "github.com/goadesign/goa/design"
. "github.com/goadesign/goa/design/dsl"
)
var _ = API("cellar", func() {
Description("A basic example of an API implemented with goa")
Scheme("http")
Host("localhost:8080")
})
var _ = Version("1.0", func() {
Title("The virtual winecellar v1.0 API")
// ... other API level properties
})
var _ = Version("2.0", func() {
Title("The virtual winecellar v2.0 API")
// ... other API level properties
})
var _ = Resource("bottle", func() {
BasePath("/bottles")
Version("1.0")
Version("2.0")
// ... other resource properties
})
var _ = Resource("bottle", func() {
BasePath("/bottles")
Version("3.0")
// ... other resource properties
})
在代码生成阶段,goagen 会将不同版本的 ServerMux
接口挂载到对应版本的 API 路由中。
在 Design 阶段中设计的每一个版本的 API 都会生成一个独立的 package,来包含其对应的 API controllers
。
在 Goagen 所生成的 server 代码中,全部都是围绕着 ServerMux
方法来检索(retrieve)顶层路由。而 Goa 底层路由的实现则是依赖于包 httprouter 。其他中间层路由均可 ServerMux
接口实现。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
上一篇: 简单使用 Goa 搭建微服务环境
下一篇: MyBatis 介绍和使用
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论