在Go语言中,如果我们需要对请求参数进行加密,可以通过使用context来实现。Context是Go标准库中的一个非常重要的组件,它用来传递request-scoped的值,比如请求的参数、超时、取消信号等,而且其实现方式非常灵活。
什么是context?
在并发编程中,我们总是需要协调各个并发调用之间的状态(比如超时退出)。context主要是用来传递request-scoped的值的。
context的作用
1. 跨越多个Goroutine,保存request-scoped状态;
2. 安全的传递request-scoped值。
context的使用
可以通过context中提供的函数WithCancel、WithDeadline、WithTimeout以及WithValue等方法,在context上下文中创建一个新的派生context并传递一些信息。
以WithValue的方式,创建含有用户ID的context并把它传递给下面的某个函数的调用:
package main
import (
"context"
"net/http"
)
func handlerWithContext(ctx context.Context, w http.ResponseWriter, r *http.Request) {
// 得到保存在context中的值
userID, ok := ctx.Value("userID").(int)
if !ok {
http.Error(w, "failed to get userID from request context", http.StatusInternalServerError)
return
}
// do something
}
func main() {
http.HandleFunc("/withcontext", func(w http.ResponseWriter, r *http.Request) {
// 创建包含用户ID的上下文,注意此处需要使用WithVlue方法
ctx := context.WithValue(r.Context(), "userID", 123)
handlerWithContext(ctx, w, r)
})
http.ListenAndServe(":8080", nil)
}
使用context对请求参数进行加密
使用context对请求参数进行加密,需要我们自定义一个中间件,并在请求处理函数中使用context传递加密后的参数。
自定义中间件
定义一个EncryptMiddleware中间件,它用来对请求中的参数进行加密,并将加密后的参数保存到request context中:
type EncryptMiddleware struct{}
func (e *EncryptMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
// 读取请求中携带的参数
temper, err := strconv.ParseFloat(r.FormValue("temper"), 2)
if err != nil {
http.Error(w, "Failed to parse query parameter.", http.StatusBadRequest)
return
}
// 加密请求参数
encrypted := encrypt(temper)
// 新建一个context并保存加密后的参数
ctx := context.WithValue(r.Context(), "encrypted", encrypted)
req := r.WithContext(ctx)
// 调用下一个处理函数
next(w, req)
}
// 加密函数
func encrypt(temper float64) string {
// 用md5来进行加密
data := []byte(strconv.FormatFloat(temper, 'f', 2, 64))
md5Sum := md5.Sum(data)
return hex.EncodeToString(md5Sum[:])
}
以上定义了一个EncryptMiddleware中间件,并定义两个函数:
1. ServeHTTP函数,其中实现了对请求参数的加密和将加密后的参数保存到上下文context中的逻辑;它还会调用下一个处理函数继续处理请求;
2. encrypt函数,用md5来进行加密参数。
在处理函数中使用上下文参数
定义一个处理函数,它会使用上面定义的EncryptMiddleware中间件来处理请求,并从上下文中取出加密后的参数:
func myHandler(w http.ResponseWriter, r *http.Request) {
// 从context中读取加密后的参数
encrypted, ok := r.Context().Value("encrypted").(string)
if !ok {
http.Error(w, "Failed to get encrypted parameter from context.", http.StatusInternalServerError)
return
}
// do something with encrypted data
}
在定义好的处理函数中,从上下文中读取到加密后的参数后,就可以对它进行对应的业务处理了。
将中间件和处理函数绑定
将处理函数和中间件绑定在一起,可以使用框架自带的mux实现如下:
func main() {
r := mux.NewRouter()
// 使用中间件
r.Use(&EncryptMiddleware{})
// 处理函数绑定
r.HandleFunc("/myhandler", myHandler)
err := http.ListenAndServe(":8080", r)
if err != nil {
log.Fatal(err)
}
}
通过该中间件,可以很方便的为请求参数实现加密处理,保证数据安全性,为业务的稳定运行提供必要的保障。