您的位置:首页 > 编程语言 > Go语言

Go实现Web后端基础功能(附源码)

2015-11-23 00:18 567 查看
前言:好一段时间没写过博客了,最近比较坎坷,感叹一下。好了,进入主题,源码在最后的链接

功能:

1、实现注册相关,包括用户名(支持中文),密码,验证码。数据库为mysql

2、登录,用session记录登录状态

3、管理,查询用户列表等,json

4、单元测试

实现:

讲一下session的实现原理,session可以通过url和cookie方式实现,推荐cookie方式,是由服务端产生并维护唯一的session id(简称sid),通过setcookie的方式设置在head头部,浏览器解析并存储,下次访问的时候浏览器会携带sid一起发起请求。服务端可以用map来存储,并用list来做垃圾回收。

mysession.go

package other

import (
"container/list"
"crypto/rand"
"encoding/base64"
"errors"
"fmt"
"io"
_ "log"
"net/http"
"net/url"
_ "reflect"
"sync"
"time"
)

type SessionManager struct {
Lock       sync.Mutex
Smap       map[string]*list.Element
SL         *list.List //gc
Cookiename string
Expires    int
}
type Session struct {
Key     string
Sid     string
Expires int
Value   interface{}
}

/*
说明:只在start中用,并已经加锁,因此这里不需要,否则会引起死锁
*/
func (sm *SessionManager) get(sid string) (Session, error) {
if element, ok := sm.Smap[sid]; ok {
sm.updateList(sid)
return *(element.Value.(*Session)), nil
}
fmt.Printf("can't find session by sid:%s\n", sid)
return *sm.NewSession("", sid, ""), errors.New("can't find session by sid")
}

func (sm *SessionManager) NewSession(key string, sid string, value interface{}) *Session {
return &Session{
Key:     key,
Sid:     sid,
Expires: sm.Expires,
Value:   value,
}
}

func (sm *SessionManager) SessionStart(w http.ResponseWriter, r *http.Request) (session Session) {
sm.Lock.Lock()
defer sm.Lock.Unlock()
cookie, err := r.Cookie(sm.Cookiename)
if err != nil || cookie.Value == "" {
sid := sm.sessionId()
session = *sm.NewSession("", sid, "")
cookie := http.Cookie{Name: sm.Cookiename, Value: url.QueryEscape(sid), Path: "/", HttpOnly: true, MaxAge: sm.Expires}
http.SetCookie(w, &cookie)
//fmt.Printf("\ncookie.value:%s,sid:%s\n", cookie.Value, sid)
//log.Printf("cookiename:%s,err:%s", cookie, err.Error())
} else {
sid, _ := url.QueryUnescape(cookie.Value)
//fmt.Printf("\nget(sid):cookie.value:%s,sid:%s\n", cookie.Value, sid)
session, _ = sm.get(sid)
//log.Printf("key:%s,cookie.value:%s,sid:%s\n", session.Key, cookie.Value, sid)
}
return
}

//垃圾回收
func (sm *SessionManager) Listen() {
sm.Lock.Lock()
defer sm.Lock.Unlock()
var n *list.Element
for e := sm.SL.Front(); e != nil; e = n {
n = e.Next()
if e.Value.(*Session).Expires == 0 {
delete(sm.Smap, e.Value.(*Session).Sid)
sm.SL.Remove(e)
} else {
e.Value.(*Session).Expires--
}
}

time.AfterFunc(time.Duration(sm.Expires)*time.Second, func() { sm.Listen() })
}

func (sm *SessionManager) GetByKey(key string) (Session, error) {
sm.Lock.Lock()
defer sm.Lock.Unlock()
for _, element := range sm.Smap {
if element.Value.(*Session).Key == key {
sm.updateList(element.Value.(*Session).Sid)
return *(element.Value.(*Session)), nil
}
}
fmt.Println("can't find session by key")
return *sm.NewSession("", "", ""), errors.New("can't find session by key")
}

func (sm *SessionManager) Set(key string, sid string) (isExits bool) {
isExits = false
if _, ok := sm.Smap[sid]; ok {
sm.SL.Remove(sm.Smap[sid])
isExits = true
}

element := sm.SL.PushBack(sm.NewSession(key, sid, ""))
sm.Smap[sid] = element
return
}

func (sm *SessionManager) Del(key string) (bl bool) {
sm.Lock.Lock()
defer sm.Lock.Unlock()
bl = false
for _, element := range sm.Smap {
if element.Value.(*Session).Key == key {
delete(sm.Smap, element.Value.(*Session).Sid)
sm.SL.Remove(element)
bl = true
}
}
return
}

//private函数,Lock之后使用,不用也不能上锁,否则死锁
func (sm *SessionManager) updateList(sid string) {

if element, ok := sm.Smap[sid]; ok {
element.Value.(*Session).Expires = sm.Expires
sm.SL.MoveToBack(element)
}
}

func (sm *SessionManager) sessionId() string {
b := make([]byte, 32)
if _, err := io.ReadFull(rand.Reader, b); err != nil {
return ""
}
return base64.URLEncoding.EncodeToString(b)
}


运行结果:





源码链接:http://download.csdn.net/detail/luomoshusheng/9291683
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: