基于版本 1.6.7

k8s的APIServer, 使用了go-restful作为其处理框架, 注册资源并接收处理 HTTP 请求.

在阅读APIServer源码之前, 需先理解go-restful主要概念.

intro

package for building REST-style Web Services using Google Go

go-restful github

go-restfu

concepts

  • Container: 一组WebService的集合, 目的: Containers for WebServices on different HTTP endpoints.
  • WebService: Route的集合; 为一组Route定义统一的 root path / 请求类型 / 响应类型
  • Route: 定义method/ULR path/调用函数/文档/参数/ curly route; 支持正则及动态谭树
  • Filter: Filters for intercepting the request → response flow on Service or Route level, 可以加global / Webservice / Route 各自的filter

init steps:

  • create container
  • create resource WebService
  • define route, path, filter and bind to route handler
  • add router to WebService
  • add WebService to container
  • new server with Handler=container
  • start server

examples

  • 示例1: use default containers
ws := new(restful.WebService)
ws.
    Path("/users").
    Consumes(restful.MIME_XML, restful.MIME_JSON).
    Produces(restful.MIME_JSON, restful.MIME_XML)

ws.Route(ws.GET("/{user-id}").To(u.findUser).
    Doc("get a user").
    Param(ws.PathParameter("user-id", "identifier of the user").DataType("string")).
    Writes(User{}))
...

func (u UserResource) findUser(request *restful.Request, response *restful.Response) {
    id := request.PathParameter("user-id")
    ...
}
  • 示例2: 含多个container
// https://github.com/emicklei/go-restful/blob/master/examples/restful-multi-containers.go
// GET http://localhost:8080/hello
// GET http://localhost:8081/hello
package main

import (
    "github.com/emicklei/go-restful"
    "io"
    "log"
    "net/http"
)

func main() {
  // add to default container
    ws := new(restful.WebService)
    ws.Route(ws.GET("/hello").To(hello))
    restful.Add(ws)
    go func() {
        log.Fatal(http.ListenAndServe(":8080", nil))
    }()

  // container 2
    container2 := restful.NewContainer()
    ws2 := new(restful.WebService)
    ws2.Route(ws2.GET("/hello").To(hello2))
    container2.Add(ws2)
    server := &http.Server{Addr: ":8081", Handler: container2}
    log.Fatal(server.ListenAndServe())
}

func hello(req *restful.Request, resp *restful.Response) {
    io.WriteString(resp, "default world")
}

func hello2(req *restful.Request, resp *restful.Response) {
    io.WriteString(resp, "second world")
}
  • 示例3: 包含 filter
// filter https://github.com/emicklei/go-restful/blob/master/examples/restful-filters.go
// Global Filter
func globalLogging(req *restful.Request, resp *restful.Response, chain *restful.FilterChain) {
    log.Printf("[global-filter (logger)] %s,%s\n", req.Request.Method, req.Request.URL)
    chain.ProcessFilter(req, resp)
}

func main() {
    // install a global (=DefaultContainer) filter (processed before any webservice in the DefaultContainer)
    restful.Filter(globalLogging)

    restful.Add(NewUserService())
    log.Print("start listening on localhost:8080")
    log.Fatal(http.ListenAndServe(":8080", nil))
}


func NewUserService() *restful.WebService {
    ws := new(restful.WebService)
    ws.
        Path("/users").
        Consumes(restful.MIME_XML, restful.MIME_JSON).
        Produces(restful.MIME_JSON, restful.MIME_XML)

    // install a webservice filter (processed before any route)
    ws.Filter(webserviceLogging).Filter(measureTime)

    // install a counter filter
    ws.Route(ws.GET("").Filter(NewCountFilter().routeCounter).To(getAllUsers))

    // install 2 chained route filters (processed before calling findUser)
    ws.Route(ws.GET("/{user-id}").Filter(routeLogging).Filter(NewCountFilter().routeCounter).To(findUser))
    return ws
}

reference