一个应用级别的变量(全局变量)使用示例
🕛 Mon, 07 Mar 2016 by GolangNote
一个应用级别的变量使用示例
type appContext struct {
db *sql.DB
}
func (c *appContext) authHandler(next http.Handler) http.Handler {
fn := func(w http.ResponseWriter, r *http.Request) {
authToken := r.Header.Get("Authorization")
user, err := getUser(c.db, authToken)
if err != nil {
http.Error(w, http.StatusText(401), 401)
return
}
context.Set(r, "user", user)
next.ServeHTTP(w, r)
}
return http.HandlerFunc(fn)
}
func (c *appContext) adminHandler(w http.ResponseWriter, r *http.Request) {
user := context.Get(r, "user")
// Maybe other operations on the database
json.NewEncoder(w).Encode(user)
}
func main() {
db := sql.Open("postgres", "...")
appC := appContext{db}
commonHandlers := alice.New(context.ClearHandler, loggingHandler, recoverHandler)
http.Handle("/admin", commonHandlers.Append(appC.authHandler).ThenFunc(appC.adminHandler))
http.Handle("/about", commonHandlers.ThenFunc(aboutHandler))
http.Handle("/", commonHandlers.ThenFunc(indexHandler))
http.ListenAndServe(":8080", nil)
}
参考文章
https://www.nicolasmerouze.com/share-values-between-middlewares-context-golang/ 3
https://joeshaw.org/net-context-and-http-handler/ 1
https://elithrar.github.io/article/custom-handlers-avoiding-globals/ 6
https://groups.google.com/forum/#!topic/golang-nuts/pCB81QylF6M 1
package main
import (
"encoding/json"
"fmt"
"net"
"net/http"
"time"
"golang.org/x/net/context"
)
type ContextHandler interface {
ServeHTTPContext(context.Context, http.ResponseWriter, *http.Request) error
}
type ContextHandlerFunc func(context.Context, http.ResponseWriter, *http.Request) error
func (f ContextHandlerFunc) ServeHTTPContext(ctx context.Context, w http.ResponseWriter, req *http.Request) error {
return f(ctx, w, req)
}
type ContextAdapter struct {
ctx context.Context
handler ContextHandler // to wrap func(context.Context, ResponseWriter, *Request) error
}
func (ca *ContextAdapter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
if err := ca.handler.ServeHTTPContext(ca.ctx, w, req); err != nil {
w.WriteHeader(http.StatusBadRequest)
json.NewEncoder(w).Encode(map[string]string{
"status": "error",
"message": err.Error(),
})
}
}
func NewRootContext(ts string) context.Context {
return context.WithValue(context.Background(), appStartTSKey, ts)
}
func main() {
rootContext := context.Background()
mainRouter := http.NewServeMux()
mainRouter.Handle("/", &ContextAdapter{
ctx: rootContext,
handler: ContextHandlerFunc(handlerRoot),
})
mainRouter.Handle("/set", &ContextAdapter{
ctx: rootContext,
handler: ContextHandlerFunc(handlerSet),
})
port := ":8080"
fmt.Println("Serving http://localhost" + port)
if err := http.ListenAndServe(port, mainRouter); err != nil {
panic(err)
}
}
func handlerRoot(ctx context.Context, w http.ResponseWriter, req *http.Request) error {
switch req.Method {
case "GET":
fmt.Println("handlerRoot")
ts, _ := getAppStartTSFromContext(ctx)
ip, _ := getIPFromContext(ctx)
ua, _ := getUserAgentFromContext(ctx)
fmt.Fprintf(w, "Root = AppStartTS: %s / IP: %v / UserAgent: %s", ts, ip, ua)
return nil
default:
http.Error(w, "Method Not Allowed", 405)
return fmt.Errorf("Method Not Allowed:", req.Method)
}
}
func handlerSet(ctx context.Context, w http.ResponseWriter, req *http.Request) error {
switch req.Method {
case "GET":
fmt.Println("handlerSet")
ts := time.Now().String()
ip, err := getIP(req)
if err != nil {
return err
}
ua := req.UserAgent()
ctx = setContextWithAppStartTS(ctx, ts)
ctx = setContextWithIP(ctx, ip)
ctx = setContextWithUserAgent(ctx, ua)
fmt.Fprintf(w, "Set = AppStartTS: %s / IP: %v / UserAgent: %s", ts, ip, ua)
return nil
default:
http.Error(w, "Method Not Allowed", 405)
return fmt.Errorf("Method Not Allowed:", req.Method)
}
}
type key int
const appStartTSKey key = 0
const userIPKey key = 1
const userAgentKey key = 2
func setContextWithAppStartTS(ctx context.Context, ts string) context.Context {
return context.WithValue(ctx, appStartTSKey, ts)
}
func setContextWithIP(ctx context.Context, userIP net.IP) context.Context {
return context.WithValue(ctx, userIPKey, userIP)
}
func setContextWithUserAgent(ctx context.Context, userAgent string) context.Context {
return context.WithValue(ctx, userAgentKey, userAgent)
}
func getAppStartTSFromContext(ctx context.Context) (string, bool) {
// ctx.Value returns nil if ctx has no value for the key;
// the string type assertion returns ok=false for nil.
ts, ok := ctx.Value(appStartTSKey).(string)
return ts, ok
}
func getIPFromContext(ctx context.Context) (net.IP, bool) {
userIP, ok := ctx.Value(userIPKey).(net.IP)
return userIP, ok
}
func getUserAgentFromContext(ctx context.Context) (string, bool) {
userAgent, ok := ctx.Value(userAgentKey).(string)
return userAgent, ok
}
// getIP extracts the user IP address from req, if present.
// https://blog.golang.org/context/userip/userip.go
func getIP(req *http.Request) (net.IP, error) {
ip, _, err := net.SplitHostPort(req.RemoteAddr)
if err != nil {
return nil, fmt.Errorf("userip: %q is not IP:port", req.RemoteAddr)
}
userIP := net.ParseIP(ip)
if userIP == nil {
return nil, fmt.Errorf("userip: %q is not IP:port", req.RemoteAddr)
}
return userIP, nil
}
本文网址: https://golangnote.com/topic/123.html (转载注明出处)
关于GolangNote:记录在工作中使用golang 遇到、面临的相关问题及解决方法。如果你在这里获得一些知识或信息,解决你的编程问题,请考虑捐赠给不幸的人或者你喜欢的慈善机构,除捐赠外,种植树木、志愿服务或减少排碳的行为也很有益处。如果你有任何问题可以在下面 留言
Be the first to comment!
Relative Articles
Recent Go Articles
- Golang 把cookie 字符串解析为cookie 结构
- Golang 计算字符串中包含某个或某些字符集的个数
- 使用Golang 对文件增删写读操作备忘
- Go Modules 使用备忘
- 使用Golang 简单删除图片exif 信息
- 谷歌翻译的 golang 库推荐
- Go 1.13.2 与1.13.3 紧急更新
- golang 人脸检测识别库
- Go build 错误 “stackcheck redeclared in this block previous declaration”的解决方法
- Golang phantomjs 动态代理实现
- Golang chrome debug protocol 库推荐
- Golang 随机打乱数组/Slice
- Golang sync.WaitGroup 的 Wait 超时处理
- Golang实现简单的Socks5代理
- Golang 用snappy + Base64 简单压缩加密进行网络传输
- Golang http IPv4/IPv6 服务
- golang 全角半角相互转换
- 在自己的网站部署TLS 1.3
- Golang 实现/打印菜单树
- Golang telegram 机器人小试
Top Go Articles
- golang 当前时间、时间戳、时区的相互转化
- golang map 按value 大小排序,降序和升序
- golang regexp 正则表达式常见的用法
- golang 正确获取绝对路径的方法
- Golang 定时循环的实现
- golang 把上传文件转为byte
- Golang 时区时差处理方式
- golang 用正则包regexp 通过user-agent 识别手机浏览器
- GoLang 正则判断字符是不是中文
- golang 生成良好的唯一ID/uuid库比较
- Golang 把cookie 字符串解析为cookie 结构
- Golang 获取两个数之间的随机数
- golang 用gzip 压缩、解压缩字符串
- GoLang 计算小文件和大文件 md5 值的例子
- Golang Web 自动安装、更新Let’s Encrypt 免费证书
- go 获取硬盘的可用空间的方法
- golang 人脸检测识别库
- Golang 生成防识别的图片验证码
- Go build 错误 “stackcheck redeclared in this block previous declaration”的解决方法
- GoLang 实现python timedelta 函数功能