参考文章
装饰器(Decorator)
Authenticate(http.HandlerFunc(w http.ResponseWriter,r *http.Request){
// Code here
})
一个简单的Authenticate实现:
func Authenticate(h http.Handler) http.Handler {
return http.HandlerFunc(w http.ResponseWriter,r *http.Request){
if !isAuth(r) {
w.WriteHeader(http.StatusForbidden)
w.Write(forbiddenMsg)
return
}
h.ServeHTTP(w, r)
}
}
这种模式允许Go开发者装饰整个类型,而不仅仅是函数。你可以为(http.ServeMux).ServeHTTP增加点东西,例如增加一些缺省的Header
var securityHeaders = map[string]string{
"Strict-Transport-Security": "max-age=31536000; includeSubDomains",
"X-XSS-Protection": "1; mode=block",
"X-Frame-Options": "SAMEORIGIN",
"X-Content-Type-Options": "nosniff",
}
type secureMux http.ServeMux
func (s *secureMux) ServeHTTP(w http.ResponseWriter, r *http.Request) {
for key, value := range securityHeaders {
w.Header().Set(key, value)
}
s.ServeMux.ServeHTTP(w, r)
}
func setup() {
// Cast the new ServeMux to a secureMux.
serveMux := secureMux(http.NewServeMux())
// Register handlers.
serveMux.Handle("/private", Authenticate(myAuthHandler))
serveMux.Handle("/settings", Authenticate(myAuthHandler))
serveMux.Handle("/", greetingsHandler)
// Use serveMux
srv := &http.Server{Handler: serveMux /* more configs here */}
if err := srv.ListenAndServe(); err != nil {
log.Println(err)
}
}
这个例子在初始阶段发现缺少的身份认证调用是很容易的:所有的handler都在一个函数中隐式地调用,而不是handler定义的地方所有的路由都在一个地方进行处理,这样你就不容易遗漏。
单例(Singleton)
- go保证
init
函数会在main
函数之前被执行,所以保证这些值可以在使用之前已经被初始化了。
var myOnlyInstance *myType
func init() {
myOnlyInstance = newMyType()
}
- 在go中实现lazy加载,可以用
sync.Once
实现
var oSingle sync.Once
var single *myType
func getSingle() *myType {
oSingle.Do(func(){ single = newMyType() })
return single
}
可以实现:
- 保证有且只有一次调用初始化
- 并发访问会被阻塞,直到初始化完成
- 初始化完成之后调用很快
信号量(Semaphore)
- 我们可以用channel来模拟信号量
type Semaphore chan struct{}
func (s Semaphore) Lock() { s <- struct{}{}}
func (s Semaphore) Unlock() { <- s }