package main
import (
"log"
"net/http"
)
// 定义"/hello" 请求处理器函数
func helloHandler(writer http.ResponseWriter, request *http.Request) {
writer.Write([]byte("你好,go web"))
}
// 定义"/world" 请求处理器函数
func worldHandler(writer http.ResponseWriter, request *http.Request) {
writer.Write([]byte("go web wrold"))
}
func main() {
// 为"/hello"路由绑定处理器函数
http.HandleFunc("/hello", helloHandler)
// 为"/world"路由绑定处理器函数
http.HandleFunc("/world", worldHandler)
// 启动服务并监听8090端口
err := http.ListenAndServe("localhost:8090", nil)
log.Fatal(err)
}
程序启动后,浏览器访问 http://localhost:8090/hello:
浏览器访问 http://localhost:8090/world:
1、url参数处理
package main
import (
"log"
"net/http"
)
func helloHandler(writer http.ResponseWriter, request *http.Request) {
method := request.Method
println(method)
url := request.URL
values := url.Query()
userName := values.Get("userName")
password := values.Get("password")
println(userName, password)
}
func main() {
http.HandleFunc("/hello", helloHandler)
err := http.ListenAndServe("localhost:8090", nil)
log.Fatal(err)
}
浏览器访问 http://localhost:8090/hello?userName=张三&password=1234 打印:请求方式 GET;张三 1234
2、form参数处理
package main
import (
"html/template"
"log"
"net/http"
)
func loginHandler(writer http.ResponseWriter, request *http.Request) {
// 获取请求方式
method := request.Method
println("请求方式", method)
// 如果此处读取了body数据则ParseForm()读取不到数据了
// body := request.Body
// length := request.ContentLength
// println("length", length)
// if length > 0 {
// p := make([]byte, length)
// body.Read(p)
// println(string(p)) // 打印:userName1=faffa&password1=fafaf
// }
if request.Method == "GET" {
// 如果时get请求则加载login.html,(该login.html与go文件同目录)
t, _ := template.ParseFiles("login.html")
t.Execute(writer, nil)
} else {
// 解析post url 参数
url := request.URL
values := url.Query()
userName := values.Get("userName")
password := values.Get("password")
println(userName, password)
// 解析表单参数
request.ParseForm()
userName1 := request.Form.Get("userName1")
password1 := request.Form.Get("password1")
println(userName1, password1)
}
}
func main() {
http.HandleFunc("/login", loginHandler)
err := http.ListenAndServe("localhost:8090", nil)
log.Fatal(err)
}
HTML表单:
<html>
<head>
<title>request 处理</title>
</head>
<body>
<form action="login?userName=张三&password=123" method="post">
用户名:<input type="text" name="userName1">
密码:<input type="password" name="password1">
<input type="submit" value="登录">
</form>
</body>
</html>
3、header参数处理
package main
import (
"fmt"
"html/template"
"log"
"net/http"
)
func headerHandler(writer http.ResponseWriter, request *http.Request) {
h := request.Header
fmt.Print(h)
println()
println("---------")
println(h.Get("User-Agent"))
}
func main() {
http.HandleFunc("/header", headerHandler)
err := http.ListenAndServe("localhost:8090", nil)
log.Fatal(err)
}
三、响应处理
1、ResponseWriter
import (
"fmt"
"html/template"
"log"
"net/http"
)
func writerHandler(writer http.ResponseWriter, request *http.Request) {
htm := `<html>
<head>
<title>request 处理</title>
</head>
<body>
<form action="login?userName=张三&password=123" method="post">
用户名:<input type="text" name="userName1">
密码:<input type="password" name="password1">
<input type="submit" value="登录">
</form>
</body>
</html>`
// 响应报文头200成功
writer.WriteHeader(200)
// 响应报文体
writer.Write([]byte(htm))
}
func main() {
http.HandleFunc("/writer", writerHandler)
err := http.ListenAndServe("localhost:8090", nil)
log.Fatal(err)
}
四、cookie
cookie是存储在浏览器端的会话信息,可存储在内容或硬盘。不设置过期时间存储在内容,设置了过期时间则存储在硬盘。
// 读取cookie
func getCookie(writer http.ResponseWriter, request *http.Request) {
cookie, err := request.Cookie("userName")
if err != nil {
log.Fatal(err)
}
println(cookie.Value)
}
// 设置cookie
func setCookie(writer http.ResponseWriter, request *http.Request) {
cookie := http.Cookie{Name: "userName", Value: "Saddam"}
http.SetCookie(writer, &cookie)
}
func main() {
http.HandleFunc("/setCookie", setCookie)
http.HandleFunc("/getCookie", getCookie)
err := http.ListenAndServe("localhost:8090", nil)
log.Fatal(err)
}
浏览器访问http://localhost:8090/setCookie设置cookie,访问http://localhost:8090/getCookie获取cookie控制台打印:Saddam。
cookie其他属性:
type Cookie struct {
Name string
Value string
Path string // optional
Domain string // optional
Expires time.Time // optional
RawExpires string // for reading cookies only
// MaxAge=0 means no 'Max-Age' attribute specified.
// MaxAge<0 means delete cookie now, equivalently 'Max-Age: 0'
// MaxAge>0 means Max-Age attribute present and given in seconds
MaxAge int
Secure bool
HttpOnly bool
SameSite SameSite
Raw string
Unparsed []string // Raw text of unparsed attribute-value pairs
}
五、session实现
相对cookie session是存储在服务的的会话信息。session拥有一个全局唯一的id和客户端关联。
1、session id
session id 使用sonyflake 生产,sonyflake的安装:
go get github.com/sony/sonyflake
2、session的存储
session信息存储在redis,redis go客户端安装
go get github.com/gomodule/redigo/redis
3、session过期
session过期使用redis的数据过期实现。
4、实现代码
1、session 操作代码
package session
import (
"log"
"reflect"
"strconv"
"github.com/gomodule/redigo/redis"
"github.com/sony/sonyflake"
)
var flake *sonyflake.Sonyflake
var redisCon *redis.Conn
func init() {
flake = sonyflake.NewSonyflake(sonyflake.Settings{})
redisCon = connRedis()
}
func connRedis() *redis.Conn {
c, err := redis.Dial("tcp", "127.0.0.1:6379")
if err != nil {
log.Fatal(err)
panic(err)
}
return &c
}
type RedisHttpSession struct {
id string
expire int
}
func NewSession(expire int) *RedisHttpSession {
id, err := flake.NextID()
if err != nil {
log.Fatal(err)
}
sesssion := &RedisHttpSession{id: strconv.FormatUint(id, 10), expire: expire}
sesssion.Set("expire", expire)
return sesssion
}
func Session(sessionId string) *RedisHttpSession {
session := &RedisHttpSession{id: sessionId}
v := session.GetValue("expire")
if v == nil {
return nil
}
if e, ok := v.([]uint8); ok {
log.Println("sessionid", session.id, "HGET key expire", "value is", string(e))
expire, _ := strconv.Atoi(string(e))
session.expire = expire
}
return session
}
func (session *RedisHttpSession) GetId() string {
return session.id
}
func (session *RedisHttpSession) Fresh() {
(*redisCon).Do("EXPIRE", session.id, session.expire)
}
func (session *RedisHttpSession) GetValue(key string) interface{} {
reply, err := (*redisCon).Do("HGET", session.id, key)
if reply != nil {
t := reflect.TypeOf(reply)
v := reflect.ValueOf(reply)
log.Println("sessionid", session.id, "HGET key", key, "reply.name", t.Name(), "reply.kind", t.Kind().String(), "reply.value", v.String(), "and error", err)
} else {
log.Println("sessionid", session.id, "HGET key", key, "and reply", reply, "and error", err)
}
return reply
}
func (session *RedisHttpSession) Delete(key string) {
(*redisCon).Do("DEL", session.id, key)
}
func (session *RedisHttpSession) Set(key string, value interface{}) {
reply, err := (*redisCon).Do("HSET", session.id, key, value)
log.Println("sessionid", session.id, "HSET key", key, "and value", value, "and reply", reply, "and error", err)
}
func (session *RedisHttpSession) Destroy() {
(*redisCon).Do("DEL", session.id)
}
2、web服务
package main
import (
"log"
"net/http"
"strconv"
"text/template"
"fa.com/wms/session"
)
func login(w http.ResponseWriter, r *http.Request) {
if r.Method == "GET" {
t, _ := template.ParseFiles("../template/login.html")
t.Execute(w, nil)
} else {
r.ParseForm()
userName := r.Form.Get("userName")
sess := session.NewSession(60)
sess.Set("userName", userName)
sess.Set("count", 0)
cookie := http.Cookie{Name: "redigosessionid", Value: sess.GetId()}
// 设置cookie保存sessionid
http.SetCookie(w, &cookie)
http.Redirect(w, r, "/myCount", http.StatusFound)
}
}
func myCount(w http.ResponseWriter, r *http.Request) {
cookie, _ := r.Cookie("redigosessionid")
sessionid := cookie.Value
sess := session.Session(sessionid)
// session 超时重新登录
if sess == nil {
http.Redirect(w, r, "/login", http.StatusFound)
return
}
count := sess.GetValue("count")
userName := sess.GetValue("userName")
sess.Fresh()
var sessUserName string
if um, ok := userName.([]uint8); ok {
sessUserName = string(um)
}
// 断言数据类型
if i, ok := count.([]uint8); ok {
sessCount, _ := strconv.Atoi(string(i))
sessCount += 1
sess.Set("count", sessCount)
// 加载html模板
t, _ := template.ParseFiles("../template/count.html")
// 准备模板数据
data := map[string]interface{}{"userName": sessUserName, "count": sessCount}
// 渲染模板数据并相应页面
t.Execute(w, data)
}
}
func main() {
http.HandleFunc("/login", login)
http.HandleFunc("/myCount", myCount)
err := http.ListenAndServe("localhost:8090", nil)
if err != nil {
log.Fatal(err)
}
}
3、登录页面
<html>
<head>
<title>登录</title>
</head>
<body>
<form action="login" method="post">
用户名:<input type="text" name="userName"><br>
密码:<input type="password" name="password"><br>
<input type="submit" value="登录">
</form>
</body>
</html>
4、session数据展示页面
go html 模板:{{.userName}} {{.count}} 模板数据占位符,分别为 userName count 占位
<html>
<head>
<title>count</title>
</head>
<body>
用户名{{.userName}} count{{.count}}
</body>
</html>