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 []byte
- user *User
- room *Room
- }
4. 建立 config 包
- package main
- import (
- "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 RedisConfig
- Server ServerConfig
- }
- // Session expiration (from github.com/boj/redistore)
- const sessionExpire = 86400 * 30
- var 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 = port
- return _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 handler
- func 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}
- }