這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
1. 避免注入(轉義)
name := url.QueryEscape(user.Name)
2. 使用 middleware 對每個請求做處理,使用 session中介層 對一類請求作處理。
中介層原理
中介層依靠 context 傳遞變數。一個請求的 context不僅僅綁定了 request和 response,還綁定了 handlers HandlersChain。所以用戶端的每個請求都會經過 middleware處理。
原理很簡單:由上可知 middleware 會對每個請求作處理。我們在中介層中定義一個 session 對象。這樣,每個請求的 context 都會儲存一個 session對象。session對象通過判斷 sessionId是否存在來判斷是否是同一個 session 對象。如果是同一個 session,那麼就可以從 session中擷取相應的值。
session 的實現機制
服務端產生一個 sessionId 儲存到 cookie中。當然還可以將 session中的所有內容儲存到 cookie中。討論前者,有了 sessionId,每次請求時會攜帶這個 sessionId的 cookie。這樣服務端就可以判斷 sessionId 是否存在來擷取相應的的 session。
3. 封裝 websocket
type connection struct {ws *websocket.Conn// send chan []byteuser *Userroom *Room}
4. 建立 config 包
package mainimport ("net/url""os""reflect")type RedisConfig struct {Host string `default:"redis://localhost:6379"`Password string `default:""`}type ServerConfig struct {Port string `default:"3000"`Secret string `default:"secret"`}type Config struct {Redis RedisConfigServer ServerConfig}// Session expiration (from github.com/boj/redistore)const sessionExpire = 86400 * 30var CONFIG = confApp()func confApp() Config {_redis := confRedis(os.Getenv("REDIS_URL"))_server := confServer(os.Getenv("PORT"))return Config{Redis: _redis,Server: _server,}}func confRedis(connUrl string) RedisConfig {_redis := RedisConfig{}typ := reflect.TypeOf(_redis)if connUrl == "" {h, _ := typ.FieldByName("Host")_redis.Host = h.Tag.Get("default")p, _ := typ.FieldByName("Password")_redis.Password = p.Tag.Get("default")return _redis}redisURL, err := url.Parse(connUrl)if err != nil {panic(err)}auth := ""if redisURL.User != nil {if password, ok := redisURL.User.Password(); ok {auth = password}}return RedisConfig{Host: redisURL.Host,Password: auth,}}func confServer(port string) ServerConfig {_conf := ServerConfig{Secret: "learngo",}typ := reflect.TypeOf(_conf)if port == "" {p, _ := typ.FieldByName("Port")_conf.Port = p.Tag.Get("default")return _conf}_conf.Port = portreturn _conf}
5. 封裝 db的 close方法到中介層
db 初始化封裝到 init 函數中
func init() {db.Connect()}
通過中介層,將 db儲存到 context中
// Connect middleware clones the database session for each request and// makes the `db` object available for each handlerfunc Connect(c *gin.Context) {s := db.Session.Clone()defer s.Close()c.Set("db", s.DB(db.Mongo.Database))c.Next()}
6. 對 action進行日誌封裝到 log檔案
type Log struct {PlayerName string `json:"playername"`Action string `json:"action"`TakeCard Card `json:"takecard"`PutCards []Card `json:"putcards"`Option string `json:"option"`}func (a *Action) ToLog(g *Game) {PutCards := make([]Card, 0)TakeCard := g.CardFromReference(a.TakeCard)for _, id := range a.PutCards {PutCards = append(PutCards, g.CardFromReference(id))}g.LastLog = &Log{a.PlayerName, a.Name, TakeCard, PutCards, a.Option}}