跳转到内容


Go 语言构建 RESTful Web 服务

Go RESTfull Web

  • 您无法回复此主题
No replies to this topic

#1 冰力

    Administrator

  • 总版主
  • 1315 帖子数:

发表于 2013/03/12 10:18:36

本文是 Hardcore Google 系列的一部分,本系列的其它部分于下面地址可以找到: 在开始着手开发网络应用之前,你需要先选择你所用的工具集,以及它们之间的相互作用,这一步很重要。在我的项目中,我选择 Go 语言作为后台,AngularJS 作为前台,而 Google App Engine 则为主机。于是,剩下的问题就是,Go 语言如何同 AngularJS 交互。幸运的是,这真的太简单了。

我选择以 REST风格的 API 进行交互,因为这样交互的方法组织良好,且网络应用的前端后端对其都支持良好。在我的开发生涯中,我发现,我为了将两种格格不如的东西统合到一起浪费了太多头脑,头发都掉了不少,REST 很好。
使用 REST 风格的网络服务器意味着你将基于 HTTP 方法(例如 GET、POST、DELETE等)和URL网址管理你的数据。在 Go 语言的一端,你可以使用 net/http 包来处理 AngularJS 提交的请求。而在更高一级,你可以这样告诉 Go 语言如何处理请求:
http.HandleFunc("/bar", func(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Thanks for the %s!", r.Method)
})

上面我们注册了一个处理所有请求 /bar 的函数。每个对请求的处理函数都有相同的函数定义: 它以参数的形式,获得输出响应的 http.ResponseWriter 和包含请求细节的 http.Request。这样,当我们启动这个服务,并发起一个 “DELETE /bar” 请求时,我们将获得 “Thanks for the DELETE!” 的返回。

我希望,你可以看看下一步的处理。在 Go 语言中实现 REST 风格的 API,你需要为每个 URL 网址节点注册处理函数,并根据给出的方法实现处理程序。通过使用 gorilla/mux 包,这个过程将更简单。它比 Go 语言默认的 HTTP 处理器更底层,但它能够更好的通过 HTTP 方法处理路由细节。下面就是例子:

m := mux.NewRouter()

// Get all lists.
m.HandleFunc("/", GetAllLists).Methods("GET")

// Make a new list.
m.HandleFunc("/", PostList).Methods("POST")

// Singe list operations.
m.HandleFunc("/{key}/", GetList).Methods("GET")
m.HandleFunc("/{key}/", PutList).Methods("PUT")
m.HandleFunc("/{key}/", DeleteList).Methods("DELETE")

// Everything else fails.
m.HandleFunc("/{path:.*}", gorca.NotFoundFunc)



如你所见,我为每个需要的 REST 方法都注册了处理程序。在这个例子里,我为网络应用的列表部分注册了一些函数。我可以通过 GET 或是 POST 在根路径( /)获取和提交列表。如果我在 URL 中设定了一个键(/{key}/),我可以处理一个指定的列表。这样,我可以通过GET, PUT和DELETE。获取列表,上传列表,或是删除列表。
最后的 HandleFunc 则用来处理其它未设定的请求。如果客户端的请求并未明确列出,我们将返回一个404状态和 JSON 格式的细节信息。net/http 包可以返回了一个简单的404状态,但我希望同时能返回 JSON响应。 使用全部抓取将允许我返回 JSON响应。客户端则可以为用户显示一个有效的信息,提示错误所在,而不仅仅是一个简单的“请求失败”。

作为处理器(handler)的例子, GetAllLists 处理器代码如下:

// GetAllLists fetches all of the lists.
func GetAllLists(w http.ResponseWriter, r *http.Request) {
    // Create the query.
    c := appengine.NewContext(r)
    q := datastore.NewQuery("List").Order("-LastModified")

    // Fetch the lists. 
    lists := []List{}
    if _, err := q.GetAll(c, &lists); err != nil {
        gorca.LogAndUnexpected(c, w, r, err)
        return
    }

    // Write the lists as JSON.
    gorca.WriteJSON(c, w, r, lists)
}


如果你对 App Engine 不是很熟悉,代码中的一些细节或许对你有些模糊,但我基本上获取了 App Engine datastore 中的所有的列表数据,并将其转换为 JSON,作为响应返回。
GetAllLists 函数显示了 Go 如何同 App Engine 相结合,使开发变得简单。短短的十几行代码,我可以创造一个强大的 REST 网络服务器。我不必处理 MySQL 的连接、用户认证、或解析传入的 HTTP 请求。 App Engine 和 Go 已经为我做了处理。最终的结果就是,我拥有了更具可读性、可测试性和可维护性的代码。


你可以在我的代码中看到我是如何为此而着迷的: 我真的惊讶于如此简易的过程。安装后台环境很可能成为一个梦魇。在工作中,我曾处理过一个 SOAP 网络服务,我愿出庭作证:这个'S'(简易的)是一个谎言。而对 Go,这根本不是什么事儿。它已经提供了强大的功能,且开源则意味着,只要你需要,大批如同 gorilla/mux 的包有的是。下一次,我将说说如何利用 Angular JS 处理我们发回的JSON。敬请期待。