Go web使用串联处理器函数登陆与写日志
假如我们需要在每次请求时,记录下每个处理器函数的日志;或者在请求需要登陆后才可见的页面时做一个统一认证,那么串联多个处理器函数就可以轻松实现这些功能。Go语言虽不是一门函数式编程语言,但它拥有一些函数式编程语言特性,如函数类型,匿名函数和闭包。我么可以将一个函数传递给另一个函数。



下面这个代码例子就演示了两个功能,一个登陆,一个写日志,没有引入第三方包,全部是标准库:
package main
import (
"fmt"
"net/http"
"reflect"
"runtime"
"time"
)
// 处理器函数
func hello(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello!")
}
// 记录请求日志,在运行时,将处理器函数的名字通过反射拿到,一并写入日志
func log(h http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
name := runtime.FuncForPC(reflect.ValueOf(h).Pointer()).Name()
fmt.Println("Handler function called - " + name)
h(w, r)
}
}
// 认证保护
func protect(h http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
if ok := Check(r); ok {
h(w, r)
} else {
http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
}
}
}
// 登陆,保存cookie
func login(w http.ResponseWriter, r *http.Request) {
expiration := time.Now()
expiration = expiration.AddDate(0, 0, 1)
uidCookie := http.Cookie{Name: "userid", Value: "token", Expires: expiration}
http.SetCookie(w, &uidCookie)
fmt.Fprintf(w, "login is ok!")
}
// 简单的cookie认证
func Check(r *http.Request) bool {
uidCookie, _ := r.Cookie("userid")
if uidCookie == nil {
return false
}
if uidCookie.Value == "token" {
return true
}
return false
}
func main() {
server := http.Server{
Addr: "127.0.0.1:8080",
}
http.HandleFunc("/login", login)
http.HandleFunc("/hello", protect(log(hello)))
server.ListenAndServe()
}
代码非常简单,一个写日志的函数(写日志时,记录是哪个函数调用,方便日后查错),一个认证保护的函数(这里简单实用cookie认证,如在生产环境可以做加密,会话等),一个cookie认证,还有两个处理器函数,分别是hello,login。我们也可以只写日志,或者只需要认证保护:log(hello)、protect(hello),下面一步步来演示它:
第一步:执行代码
> go run server.go
第二步:在浏览器输入 http://localhost:8080/hello

在没有登陆,没有把cookie写入客户端情况下,访问被保护的页面是显示无权访问,这样就可以保护我们需要登陆认证的页面。
第三步:在浏览器输入 http://localhost:8080/login

请求这个页面就是写入cookie到客户端,也就是我们常常的登陆请求,这里是简单的写cookie,生产环境的要复杂一些。
第四步:在浏览器再次输入 http://localhost:8080/hello

这次再访问这个页面就可以看见我们想要看的内容了,认证通过。
Posted by 何敏 on 2019/1/17 01:14:18