Add en/0.6.x.md syntax highlighting
This commit is contained in:
46
en/06.2.md
46
en/06.2.md
@@ -34,7 +34,7 @@ Next, we'll examine a complete example of a Go session manager and the rationale
|
||||
### Session manager
|
||||
|
||||
Define a global session manager:
|
||||
|
||||
```Go
|
||||
type Manager struct {
|
||||
cookieName string //private cookiename
|
||||
lock sync.Mutex // protects session
|
||||
@@ -49,40 +49,40 @@ Define a global session manager:
|
||||
}
|
||||
return &Manager{provider: provider, cookieName: cookieName, maxlifetime: maxlifetime}, nil
|
||||
}
|
||||
|
||||
```
|
||||
Create a global session manager in the `main()` function:
|
||||
|
||||
```Go
|
||||
var globalSessions *session.Manager
|
||||
// Then, initialize the session manager
|
||||
func init() {
|
||||
globalSessions = NewManager("memory","gosessionid",3600)
|
||||
}
|
||||
|
||||
```
|
||||
We know that we can save sessions in many ways including in memory, the file system or directly into the database. We need to define a `Provider` interface in order to represent the underlying structure of our session manager:
|
||||
|
||||
```Go
|
||||
type Provider interface {
|
||||
SessionInit(sid string) (Session, error)
|
||||
SessionRead(sid string) (Session, error)
|
||||
SessionDestroy(sid string) error
|
||||
SessionGC(maxLifeTime int64)
|
||||
}
|
||||
|
||||
```
|
||||
- `SessionInit` implements the initialization of a session, and returns a new session if it succeeds.
|
||||
- `SessionRead` returns a session represented by the corresponding sid. Creates a new session and returns it if it does not already exist.
|
||||
- `SessionDestroy` given an sid, deletes the corresponding session.
|
||||
- `SessionGC` deletes expired session variables according to `maxLifeTime`.
|
||||
|
||||
So what methods should our session interface have? If you have any experience in web development, you should know that there are only four operations for sessions: set value, get value, delete value and get current session id. So, our session interface should have four methods to perform these operations.
|
||||
|
||||
```Go
|
||||
type Session interface {
|
||||
Set(key, value interface{}) error //set session value
|
||||
Get(key interface{}) interface{} //get session value
|
||||
Delete(key interface{}) error //delete session value
|
||||
SessionID() string //back current sessionID
|
||||
}
|
||||
|
||||
```
|
||||
This design takes its roots from the `database/sql/driver`, which defines the interface first, then registers specific structures when we want to use it. The following code is the internal implementation of a session register function.
|
||||
|
||||
```Go
|
||||
var provides = make(map[string]Provider)
|
||||
|
||||
// Register makes a session provider available by the provided name.
|
||||
@@ -97,11 +97,11 @@ This design takes its roots from the `database/sql/driver`, which defines the in
|
||||
}
|
||||
provides[name] = provider
|
||||
}
|
||||
|
||||
```
|
||||
### Unique session id's
|
||||
|
||||
Session id's are for identifying users of web applications, so they must be unique. The following code shows how to achieve this goal:
|
||||
|
||||
```Go
|
||||
func (manager *Manager) sessionId() string {
|
||||
b := make([]byte, 32)
|
||||
if _, err := io.ReadFull(rand.Reader, b); err != nil {
|
||||
@@ -109,11 +109,11 @@ Session id's are for identifying users of web applications, so they must be uniq
|
||||
}
|
||||
return base64.URLEncoding.EncodeToString(b)
|
||||
}
|
||||
|
||||
```
|
||||
### Creating a session
|
||||
|
||||
We need to allocate or get an existing session in order to validate user operations. The `SessionStart` function is for checking the existence of any sessions related to the current user, and creating a new session if none is found.
|
||||
|
||||
```Go
|
||||
func (manager *Manager) SessionStart(w http.ResponseWriter, r *http.Request) (session Session) {
|
||||
manager.lock.Lock()
|
||||
defer manager.lock.Unlock()
|
||||
@@ -129,9 +129,9 @@ We need to allocate or get an existing session in order to validate user operati
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
```
|
||||
Here is an example that uses sessions for a login operation.
|
||||
|
||||
```Go
|
||||
func login(w http.ResponseWriter, r *http.Request) {
|
||||
sess := globalSessions.SessionStart(w, r)
|
||||
r.ParseForm()
|
||||
@@ -144,13 +144,13 @@ Here is an example that uses sessions for a login operation.
|
||||
http.Redirect(w, r, "/", 302)
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
### Operation value: set, get and delete
|
||||
|
||||
The `SessionStart` function returns a variable that implements a session interface. How do we use it?
|
||||
|
||||
You saw `session.Get("uid")` in the above example for a basic operation. Now let's examine a more detailed example.
|
||||
|
||||
```Go
|
||||
func count(w http.ResponseWriter, r *http.Request) {
|
||||
sess := globalSessions.SessionStart(w, r)
|
||||
createtime := sess.Get("createtime")
|
||||
@@ -170,7 +170,7 @@ You saw `session.Get("uid")` in the above example for a basic operation. Now let
|
||||
w.Header().Set("Content-Type", "text/html")
|
||||
t.Execute(w, sess.Get("countnum"))
|
||||
}
|
||||
|
||||
```
|
||||
As you can see, operating on sessions simply involves using the key/value pattern in the Set, Get and Delete operations.
|
||||
|
||||
Because sessions have the concept of an expiry time, we define the GC to update the session's latest modify time. This way, the GC will not delete sessions that have expired but are still being used.
|
||||
@@ -178,8 +178,8 @@ Because sessions have the concept of an expiry time, we define the GC to update
|
||||
### Reset sessions
|
||||
|
||||
We know that web applications have a logout operation. When users logout, we need to delete the corresponding session. We've already used the reset operation in above example -now let's take a look at the function body.
|
||||
|
||||
//Destroy sessionid
|
||||
```Go
|
||||
// Destroy sessionid
|
||||
func (manager *Manager) SessionDestroy(w http.ResponseWriter, r *http.Request){
|
||||
cookie, err := r.Cookie(manager.cookieName)
|
||||
if err != nil || cookie.Value == "" {
|
||||
@@ -193,11 +193,11 @@ We know that web applications have a logout operation. When users logout, we nee
|
||||
http.SetCookie(w, &cookie)
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
### Delete sessions
|
||||
|
||||
Let's see how to let the session manager delete a session. We need to start the GC in the `main()` function:
|
||||
|
||||
```Go
|
||||
func init() {
|
||||
go globalSessions.GC()
|
||||
}
|
||||
@@ -208,7 +208,7 @@ Let's see how to let the session manager delete a session. We need to start the
|
||||
manager.provider.SessionGC(manager.maxlifetime)
|
||||
time.AfterFunc(time.Duration(manager.maxlifetime), func() { manager.GC() })
|
||||
}
|
||||
|
||||
```
|
||||
We see that the GC makes full use of the timer function in the `time` package. It automatically calls GC when the session times out, ensuring that all sessions are usable during `maxLifeTime`. A similar solution can be used to count online users.
|
||||
|
||||
## Summary
|
||||
|
||||
Reference in New Issue
Block a user