golang学习之go web 开发

一、hello world

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>

猜你喜欢

转载自blog.csdn.net/weixin_56349119/article/details/126201411