本节实现了分布式缓存 HTTP 服务端的搭建,最终代码结构如下:
1 2 3 4 5 6 7 8 9
| lru/ |--lru.go |--lru_test.go byteview.go cache.go dawncache.go dawncache_test.go go.mod http.go
|
HTTP 服务端
http.go
HTTPPool
构建结构体 HTTPPool 用于作为服务端,用于响应查询缓存数据的请求:
1 2 3 4 5 6 7 8 9 10 11 12 13
| const defaultBasePath = "/_dawncache/"
type HTTPPool struct { self string basePath string }
func NewHTTPPool(self string) *HTTPPool { return &HTTPPool{ self: self, basePath: defaultBasePath, } }
|
实现 http.Handler 接口
当 HTTPPool 实现了 http.Handler 接口时,可以传入 http.ListenAndServe 函数作为第二个参数。
而 http.Handler 的接口定义如下:
1 2 3
| type Handler interface { ServeHTTP(ResponseWriter, *Request) }
|
所以 HTTPPool 需要实现 ServeHTTP 方法,以此实现 http.Handler 接口。ServeHTTP 中的主要逻辑就是从 URL.Path 中提取出 groupName 和 key,并在相应的 group 中查询缓存数据并响应 HTTP 请求。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| func (p *HTTPPool) Log(format string, v ...interface{}) { log.Printf("[server %s] %s", p.self, fmt.Sprintf(format, v...)) }
func (p *HTTPPool) ServeHTTP(w http.ResponseWriter, r *http.Request) { if !strings.HasPrefix(r.URL.Path, p.basePath) { http.Error(w, "HTTPPool serving unexpected path: "+r.URL.Path, http.StatusBadRequest) return }
parts := strings.SplitN(r.URL.Path[len(p.basePath):], "/", 2) if len(parts) != 2 { http.Error(w, "bad request", http.StatusBadRequest) return }
groupName := parts[0] key := parts[1]
group := GetGroup(groupName) if group == nil { http.Error(w, "no such group:"+groupName, http.StatusBadRequest) return }
view, err := group.Get(key) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return }
w.Header().Set("Content-Type", "application/octet-stream") w.Write(view.ByteSlice()) }
|