GoWeb

本文详细介绍了如何使用GoWeb创建Web应用,包括使用gobuild和goinstall构建服务器,通过net/http包处理HTTP请求,以及使用模板引擎和会话管理。涵盖了HTTP协议、服务器配置、静态文件处理、动作和模板示例等内容。
摘要由CSDN通过智能技术生成

GoWeb

GoWeb应用原理

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jKcRfp9k-1623597877761)(C:\Users\51936\AppData\Roaming\Typora\typora-user-images\image-20210411115121803.png)]

创建一个web应用

在终端执行命令
  • 在目录中右键在命令提示符中打开执行 go build main.go 命令;然后在当前目录中就会生成一个 main.exe 的二进制可执行文件;最后再执行 main.exe 就可以启动服务器

  • 在目录中右键在命令提示符中打开执行 go install webapp 命令;然后在 bin 目录中会生成一个 .exe

    的二进制可执行文件;进入 bin 目录之后再 bin 目录中执行 .exe 就可以启动服务器

  • 在浏览器地址栏输入 http://localhost:8080,在浏览器中就会显示 Hello World! /在浏览器地址栏输入 http://localhost:8080/hello,在浏览器中就会显示 Hello World! /hello

搭建服务器

  • 通过 net/http 包调用 ListenAndServe 函数并传入网络地址以及负责处理请求的处理器( handler )作为参数。如果网络地址参数为空字符串,服务器默认使用 80 端口进行网络连接;如果处理器参数为 nil,服务器将使用默认的多路复用器 DefaultServeMux,当然,我们也可以通过调用 NewServeMux 函数创建一个多路复用器。多路复用器接收到用户的请求之后根据请求的 URL 来判断使用哪个处理器来处理请求,找到后就会重定向到对应的处理器来处理请求。
  • Go语言中的HandlerFunc函数类型可以将一个带有正确签名的函数f转换成一个带有方法f的Handler
使用处理器函数处理请求
package main

import (
	"fmt"
	"net/http"
	//提供了HTTP客户端和服务端的实现
)

//创建处理器函数
func handler(w http.ResponseWriter,r *http.Request) {
	fmt.Fprintln(w,"Hello world!",r.URL.Path)
	//Fprintln采用默认格式将其参数格式化并写入w。
	//总是会在相邻参数的输出之间添加空格并在输出结束后添加换行符。
	//返回写入的字节数和遇到的任何错误。
}
//http.ResponseWriter接口被HTTP处理器用于构造HTTP回复

func main(){
	http.HandleFunc("/",handler)
	//type HandlerFunc func(ResponseWriter, *Request)
	//HandlerFunc type是一个适配器
	//通过类型转换让我们可以将普通的函数作为HTTP处理器使用。
	//如果f是一个具有适当签名的函数
	//HandlerFunc(f)通过调用f实现了Handler接口。
    //func HandleFunc(pattern string, handler func(ResponseWriter, *Request))
    //HandleFunc注册一个处理器函数handler和对应的模式pattern(注册到DefaultServeMux)

	//创建路由
	http.ListenAndServe(":8080",nil)
	//func ListenAndServe(addr string, handler Handler) error
	//ListenAndServe监听TCP地址addr
	//并且会使用handler参数调用Serve函数处理接收到的连接
	//handler参数一般会设为nil,此时会使用DefaultServeMux。
}
使用处理器处理请求
package main

import (
	"fmt"
	"net/http"
)

type MyHandler struct {}

func (m *MyHandler) ServeHTTP(w http.ResponseWriter,r *http.Request) {
	fmt.Fprintln(w,"通过自己创建的处理器处理请求...")
}

func main(){
	myHandler := MyHandler{}

	http.Handle("/myHandler",&myHandler)
    //func Handle(pattern string, handler Handler)
    //Handle注册HTTP处理器handler和对应的模式pattern(注册到DefaultServeMux)。如果该模式已经注册有一个处理器,Handle会panic

	http.ListenAndServe(":8080",nil)

}
  • 处理器Handler

    • type Handler interface {
          ServeHTTP(ResponseWriter, *Request)
      }
      
    • 实现了Handler接口的对象可以注册到HTTP服务端,为特定的路径及其子树提供服务。

    • ServeHTTP应该将回复的头域和数据写入ResponseWriter接口然后返回。返回标志着该请求已经结束,HTTP服务端可以转移向该连接上的下一个请求。

通过 Server 结构对服务器进行更详细的配置
package main

import (
	"fmt"
	"net/http"
	"time"
)

type MyHandler struct {}

func (m *MyHandler) ServeHTTP(w http.ResponseWriter,r *http.Request) {
	fmt.Fprintln(w,"通过自己创建的处理器处理请求...")
}

func main(){
	myHandler := MyHandler{}

	server := http.Server{
		Addr: ":8080",
		Handler: &myHandler,
		ReadHeaderTimeout: 2*time.Second,
	}
	
	server.ListenAndServe()

}
创建多路复用器
package main
import (
	"fmt"
	"net/http"
)
func handler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintln(w, "通过自己创建的多路复用器来处理请求")
}
func main() {
	mux := http.NewServeMux()
	mux.HandleFunc("/myMux", handler)
	http.ListenAndServe(":8080", mux)
}

Http协议

  • HTTP 超文本传输协议 (HTTP-Hypertext transfer protocol),是一个属于应用层的

    面向对象的协议,是一种详细规定了浏览器和万维网服务器之间互相通信的规则,通过因特网传送万维网文档的数据传送协议。

  • 客户端与服务端通信时传输的内容我们称之为报文。HTTP 就是一个通信规则,这个规则规定了客户端发送给服务器的报文格式,也规定了服务器发送给客户端的报文格式。客户端发送给服务器的称为”请求报文“,服务器发送给客户端的称为”响应报文“。

Http协议会话方式

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Hwc0MrwU-1623597877763)(C:\Users\51936\AppData\Roaming\Typora\typora-user-images\image-20210411142254738.png)]

  • 浏览器与 WEB 服务器的连接过程是短暂的,每次连接只处理一个请求和响应。对每一

    个页面的访问,浏览器与 WEB 服务器都要建立一次单独的连接。

  • 浏览器到 WEB 服务器之间的所有通讯都是完全独立分开的请求和响应对。

报文
报文格式

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-R18wI30L-1623597877765)(C:\Users\51936\AppData\Roaming\Typora\typora-user-images\image-20210411142519075.png)]

请求报文
  • 报文格式

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Xm4lR6qy-1623597877767)(C:\Users\51936\AppData\Roaming\Typora\typora-user-images\image-20210411144953374.png)]

  • Get请求

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qD05YWyA-1623597877769)(C:\Users\51936\AppData\Roaming\Typora\typora-user-images\image-20210411145015653.png)]

  • Get请求没有请求体,Post请求才有请求体

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dQR7tzQV-1623597877770)(C:\Users\51936\AppData\Roaming\Typora\typora-user-images\image-20210411145339807.png)]

  • Post请求

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BqMMXjwn-1623597877771)(C:\Users\51936\AppData\Roaming\Typora\typora-user-images\image-20210411145433057.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IvUuFH3W-1623597877772)(C:\Users\51936\AppData\Roaming\Typora\typora-user-images\image-20210411145454209.png)]

  • 响应报文

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nTGjiunz-1623597877773)(C:\Users\51936\AppData\Roaming\Typora\typora-user-images\image-20210411145702917.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TcetWOfl-1623597877774)(C:\Users\51936\AppData\Roaming\Typora\typora-user-images\image-20210411145736868.png)]

  • 响应状态码

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kksRpjlg-1623597877774)(C:\Users\51936\AppData\Roaming\Typora\typora-user-images\image-20210411145843367.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RLlFoeJD-1623597877775)(C:\Users\51936\AppData\Roaming\Typora\typora-user-images\image-20210411145905793.png)]

处理器请求

  • GO的net/http包提供了一系列用于表示HTTP报文的结构,可以使用它处理请求和发送相应,其中Request结构代表了客户端发送的请求报文
  • Request类型代表一个服务端接受到的或者客户端发送出去的HTTP请求
获取请求URL
package main

import (
	"fmt"
	"net/http"
)

//创建处理器函数
func handler (w http.ResponseWriter,r *http.Request){
	fmt.Fprintln(w,"你发送的请求的请求地址是:",r.URL.Path)
	fmt.Fprintln(w,"你发送的请求的请求地址后的查询字符串是:",r.URL.RawQuery)
	// URL在服务端表示被请求的URI,在客户端表示要访问的URL。
	// 在服务端,URL字段是解析请求行的URI(保存在RequestURI字段)得到的,
	// 对大多数请求来说,除了Path和RawQuery之外的字段都是空字符串。
	// 在客户端,URL的Host字段指定了要连接的服务器,
	// 而Request的Host字段(可选地)指定要发送的HTTP请求的Host头的值。
	
	//Path字段
	//获取请求的URL
	//RawQuery字段
	//获取请求的URL后面?后面的查询字符串
	
}

func main(){
	http.HandleFunc("/hello",handler)
	http.ListenAndServe(":8080",nil)
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Pk6Kkk4i-1623597877776)(GoWeb.assets/image-20210414115000286.png)]

获取请求头和请求体
  • 通过Request结果中的Header字段用来获取请求头中的所有信息,Header字段的类型是Header类型,而Header类型是map[string] []string
package main

import (
	"fmt"
	"net/http"
)

//创建处理器函数
func handler (w http.ResponseWriter,r *http.Request){
	fmt.Fprintln(w,"你发送的请求的请求地址是:",r.URL.Path)
	fmt.Fprintln(w,"你发送的请求的请求地址后的查询字符串是:",r.URL.RawQuery)

	fmt.Fprintln(w,"请求头中的所有信息有:",r.Header)
	//type Header map[string][]string
	//Header代表HTTP头域的键值对。
	fmt.Fprintln(w,"请求头中的Accept-Encoding的信息是:",r.Header["Accept-Encoding"])
	fmt.Fprintln(w,"请求头终Accept-Encoding的属性值是:",r.Header.Get("Accept-Encoding"))
	//func (h Header) Get(key string) string
	//Get返回键对应的第一个值,如果键不存在会返回""。如要获取该键对应的值切片,请直接用规范格式的键访问map

	//获取请求体中内容长度
	len := r.ContentLength
	//创建byte切片
	body := make([]byte,len)
	//将请求体中的内容读到body中
	r.Body.Read(body)
	//在浏览器中显示请求体中的内容
	fmt.Fprintln(w,"请求体中的内容:",string(body))

}

func main(){
	http.HandleFunc("/hello",handler)
	http.ListenAndServe(":8080",nil)
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cAL0uvtL-1623597877776)(GoWeb.assets/image-20210414120708217.png)]

获取请求参数
  • 通过net/http库中的Request结构的字段以及方法获取请求URL后面的请求参数以及form表单中提交的请求参数
package main

import (
	"fmt"
	"net/http"
)

//创建处理器函数
func handler (w http.ResponseWriter,r *http.Request){

	//解析表单,在调用rForm前必须执行该操作
	r.ParseForm()
	//获取请求参数
	//如果form表单的action属性的URL地址中也有form表单参数名相同的请求参数
	//那么参数值都可以得到,并且form表单中的参数值在ULR参数值的前面
	fmt.Fprintln(w,"请求参数有:",r.Form)
	fmt.Fprintln(w,"POS请求的form表单中的请求参数有:",r.PostForm)

}

func main(){
	http.HandleFunc("/hello",handler)
	http.ListenAndServe(":8080",nil)
}

  • 但是 PostForm 字段只支持 application/x-www-form-urlencoded 编码,如果form 表单的 enctype 属性值为 multipart/form-data,那么使用 PostForm 字段无法获取表单中的数据,此时需要使用 MultipartForm 字段
  • form 表单的 enctype 属性的默认值是 application/x-www-form-urlencoded 编 码 , 实 现 上 传 文 件 时 需 要 讲 该 属 性 的 值 设 置 为multipart/form-data 编码格式
package main

import (
	"fmt"
	"net/http"
)

//创建处理器函数
func handler (w http.ResponseWriter,r *http.Request){

	//通过直接调用FormValue方法和PostFormValue方法直接获取请求参数的值
	fmt.Fprintln(w,"URL中的user请求参数是:",r.FormValue("user"))
	fmt.Fprintln(w,"Form表单的user请求参数的值是:",r.PostFormValue("username"))
}

func main(){
	http.HandleFunc("/hello",handler)
	http.ListenAndServe(":8080",nil)
}

模板引擎

  • Go 为我们提供了 text/template 库和 html/template 库这两个模板引擎,模板引擎通过将数据和模板组合在一起生成最终的 HTML,而处理器负责调用模板引擎并将引擎生成的 HTMl 返回给客户端。
  • Go 的模板都是文本文档(其中 Web 应用的模板通常都是 HTML),它们都嵌入了一些称为动作的指令。从模板引擎的角度来说,模板就是嵌入了动作的文本(这些文本通常包含在模板文件里面),而模板引擎则通过分析并执行这些文本来生成出另外一些文本。
使用 Go 的 Web 模板引擎步骤:
  • 对文本格式的模板源进行语法分析,创建一个经过语法分析的模板结构,其中模板源既可以是一个字符串,也可以是模板文件中包含的内容。
  • 执行经过语法分析的模板,将 ResponseWriter 和模板所需的动态数据传递给模板引擎,被调用的模板引擎会把经过语法分析的模板和传入的数据结合起来,生成出最终的 HTML,并将这些 HTML 传给ResponseWriter。
package main

import (
	"html/template"
	"net/http"
)

//创建处理器函数
func testTemplate(w http.ResponseWriter,r *http.Request){

	//解析模板
	t,_ := template.ParseFiles("index.html")
	//func ParseFiles(filenames ...string) (*Template, error)
	//ParseFiles函数创建一个模板并解析filenames指定的文件里的模板定义。
	//返回的模板的名字是第一个文件的文件名(不含扩展名),内容为解析后的第一个文件的内容。至少要提供一个文件。
	//如果发生错误,会停止解析并返回nil。
	//当我们调用 ParseFiles 函数解析模板文件时,Go 会创建一个新的模板,
	//并将给定的模板文件的名字作为新模板的名字,如果该函数中传入了多个
	//文件名,那么也只会返回一个模板,而且以第一个文件的文件名作为模板
	//的名字,至于其他文件对应的模板则会被放到一个 map 中
	
	//在解析模板时都没有对错误进行处理,Go 提供了一个 Must 函数专
	//门用来处理这个错误。Must 函数可以包裹起一个函数,被包裹的函数会
	//返回一个指向模板的指针和一个错误,如果错误不是 nil,那么 Must 函数
	//将产生一个 panic。

	//执行
	t.Execute(w,"")
	//func (t *Template) Execute(wr io.Writer, data interface{}) error
	//Execute方法将解析好的模板应用到data上,并将输出写入wr。
	//如果执行时出现错误,会停止执行,但有可能已经写入wr部分数据。模板可以安全的并发执行。
}



func main(){
	http.HandleFunc("/testTemplate",testTemplate)
	http.ListenAndServe(":8080",nil)
}

处理静态文件

  • 对于HTML页面中的css以及js等静态文件,需要使用net/http包下的方法处理

动作

  • Go 模板的动作就是一些嵌入到模板里面的命令,这些命令在模板中需要放到两个大括号里**{{** 动作 }}
条件动作
package main

import (
	"html/template"
	"net/http"
)

func testIf(w http.ResponseWriter,r *http.Request){
	//解析模板文件
	t := template.Must(template.ParseFiles("D:/gocode/src/go_code/test/main/if.html"))
	age := 17
	//执行
	t.Execute(w,age>18)
}

func main(){
	http.HandleFunc("/testIf",testIf)
	http.ListenAndServe(":8080",nil)
}
<html>
    <head>
        <meta charset="UTF-8"/>
    </head>
    <body>
        {{if.}}
        我要显示出来
        {{end}}
        <hr />
        {{if.}}
        如果传过来的是true将显示这部分内容
        {{else}}
            else中的内容被显示
        {{end}}
    </body>
</html>
迭代动作
  • 迭代动作可以对数组、切片、映射或者通道进行迭代
//格式一
{{range.}}
遍历到的元素是{{.}}
{{end}}

//格式二
{{range.}}
遍历到的元素是{{.}}
{{else}}
没有任何元素
{{end}}
//range后面的.代表被遍历的元素,要显示的内容里面的点代表遍历到的元素

//方式获取
{{range.}}
获取结构体的Name字段名{{.Name}}
{{end}}

//迭代获取Map是可以设置变量,变量以$开头
{{range $k,$v :=.}}
键值是{{$k}},值是{{$v}}
{{end}}

//迭代管道
{{c1|c2|c3}}
//c1c2c3可以是参数或者函数,管道允许用户将一个参数的输出传递给下一个参数,各个参数之间使用|分割

设置动作
  • 允许在指定范围内对**.**设置值
//格式一
{{with arg}}
传过来的数据设置的新值是{{.}}

//格式二
{{with arg}}
传过来的数据设置的新值是{{.}}
{{else}}
传过来的数据仍然是{{.}}
{{end}}
包含动作
  • 允许用户在一个模板里面包含另一个模板,从而构建出嵌套的模板
//格式一
{{template "name"}}
//name为被包含的模板的名字
//格式二
{{template "name" arg}}
//arg是用户想要传递给嵌套模板的数据
定义动作
  • 访问一些网站时,会看到网页中有相同的部分:比如导航栏、版权

    信息、联系方式等。这些相同的布局可以通过定义动作在模板文件中定义模板来实现。定义模板的格式是:以**{{ define “layout” }}开头,以{{ end }}**结尾。

块动作
  • Go 1.6 引入了一个新的块动作,这个动作允许用户定义一个模板并立即使用。相当于设置了一个默认的模板
//格式
{{block arg}}
如果找不到模板我就要显示了
{{end}}
例子
package main

import (
	"html/template"
	"net/http"
	"web03_actions/model"
)

//测试range
func testRange(w http.ResponseWriter, r *http.Request) {
	//解析模板文件
	t := template.Must(template.ParseFiles("range.html"))
	var emps []*model.Employee
	emp := &model.Employee{
		ID:       1,
		LastName: "李小璐",
		Email:    "lxl@jnl.com",
	}
	emps = append(emps, emp)
	emp2 := &model.Employee{
		ID:       2,
		LastName: "白百何",
		Email:    "bbh@cyf.com",
	}
	emps = append(emps, emp2)
	emp3 := &model.Employee{
		ID:       3,
		LastName: "马蓉",
		Email:    "mr@wbq.com",
	}
	emps = append(emps, emp3)

	//执行
	t.Execute(w, emps)
}

//测试if
func testIf(w http.ResponseWriter, r *http.Request) {
	//解析模板文件
	t := template.Must(template.ParseFiles("if.html"))
	age := 17
	//执行
	t.Execute(w, age > 18)
}

//测试with
func testWith(w http.ResponseWriter, r *http.Request) {
	//解析模板文件
	t := template.Must(template.ParseFiles("with.html"))
	//执行
	t.Execute(w, "狸猫")
}

//测试template
func testTemplate(w http.ResponseWriter, r *http.Request) {
	//解析模板文件
	t := template.Must(template.ParseFiles("template1.html", "template2.html"))
	//执行
	t.Execute(w, "我能在两个文件中显示吗?")
}

//测试define
func testDefine(w http.ResponseWriter, r *http.Request) {
	//解析模板文件
	t := template.Must(template.ParseFiles("define.html"))
	//执行
	t.ExecuteTemplate(w, "model", "")
}

//测试testDefine2
func testDefine2(w http.ResponseWriter, r *http.Request) {
	age := 17
	var t *template.Template
	if age < 18 {
		//解析模板文件
		t = template.Must(template.ParseFiles("define2.html"))
	} else {
		//解析模板文件
		t = template.Must(template.ParseFiles("define2.html", "content1.html"))
	}
	//执行
	t.ExecuteTemplate(w, "model", "")
}

func main() {
	http.HandleFunc("/testIf", testIf)
	http.HandleFunc("/testRange", testRange)
	http.HandleFunc("/testWith", testWith)
	http.HandleFunc("/testTemplate", testTemplate)
	http.HandleFunc("/testDefine", testDefine)
	http.HandleFunc("/testDefine2", testDefine2)

	http.ListenAndServe(":8080", nil)
}

//content1
<html>
    <head>
        <meta charset="UTF-8"/>
    </head>
    <body>
       {{define "content"}}
            我已经是一个成年人!
       {{end}}
    </body>
</html>
//content2
<html>
    <head>
        <meta charset="UTF-8"/>
    </head>
    <body>
        {{define "content"}}
         我还未成年!
        {{end}}
    </body>
</html>
//define
<!-- 定义模板 -->
{{define "model"}}
<html>
    <head>
        <meta charset="UTF-8"/>
    </head>
    <body>
       {{template "contennt"}}
    </body>
</html>
{{end}}

{{define "contennt"}}
    <a href="https://www.baidu.com">百度</a>
{{end}}
//define2
<!-- 定义模板 -->
{{define "model"}}
<html>
    <head>
        <meta charset="UTF-8"/>
    </head>
    <body>
       <!-- 块动作,相当于一个默认的模板 -->
        {{block "content" .}}
            你的年龄是假的吧!
        {{end}} 
    </body>
</html>
{{end}}

//if
<html>
    <head>
        <meta charset="UTF-8"/>
    </head>
    <body>
       {{if .}}
        我要显示出来
        {{end}}
        <hr />
        {{if .}}
         如果传过来的是true将显示这部门内容
        {{else}}
           else中的内容被显示
        {{end}}    
    </body>
</html>
<html>
    <head>
        <meta charset="UTF-8"/>
    </head>
    <body>
        {{range .}}
            遍历到的元素是:
            {{.}}<br>
            <a href="#">{{.LastName}}</a>
        {{else}}
            没有遍历到任何元素
        {{end}}        
    </body>
</html>
//template1
<html>
    <head>
        <meta charset="UTF-8"/>
    </head>
    <body>
       <div>后台传过来的数据是:{{.}}</div>
       <div>包含template2.html里面的内容</div>
       {{template "template2.html"}}
       <hr/>
       <div>将template1.html中得到的数据传入到template2.html后</div>
       {{template "template2.html" .}}
    </body>
</html>
//template2
<html>
    <head>
        <meta charset="UTF-8"/>
    </head>
    <body>
       <div>template2.html里面传入的数据是:{{.}}</div>
    </body>
</html>
//with
<html>
    <head>
        <meta charset="UTF-8"/>
    </head>
    <body>
      {{with "太子"}}
        <div>修改之后的数据是:{{.}}</div>
       {{end}} 
       <hr/>
       {{with ""}}
       <div>修改之后的数据是:{{.}}</div>
       {{else}}
       <div>传过来的数据仍是:{{.}}</div>
       {{end}}
    </body>
</html>

会话控制

  • HTTP 是无状态协议,服务器不能记录浏览器的访问状态,也就是说服务器不能区分中两次请求是否由同一个

    客户端发出。这样的设计严重阻碍的 Web 程序的设计。如:在进行网购时,买了一条裤子,又买了一个手机。由于 http 协议是无状态的,如果不通过其他手段,服务器是不能知道用户到底买了什么。而 Cookie 就是解决方案之一

Cookie
  • Cookie 实际上就是服务器保存在浏览器上的一段信息。浏览器有了 Cookie 之后,每次向服务器发送请求时都会同时将该信息发送给服务器,服务器收到请求后,就可以根据该信息处理请求

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pUgMGIM6-1623597877777)(GoWeb.assets/image-20210421163830971.png)]

Cookie运行方式
  • 第一次向服务器发送请求时在服务器端创建 Cookie
  • 将在服务器端创建的 Cookie 以响应头的方式发送给浏览器
  • 以后再发送请求浏览器就会携带着该 Cookie
  • 服务器得到 Cookie 之后根据 Cookie 的信息来区分不同的用户
创建cookie并发送给浏览器
package main

import (
	"fmt"
	"net/http"
)

//setCookie添加Cookie
func setCookie(w http.ResponseWriter,r *http.Request) {
	//创建cookie
	cookie := http.Cookie{
		Name:     "user",
		Value:    "admin",
		HttpOnly: true,
		MaxAge: 60,
	}

	cookie2 := http.Cookie{
		Name:     "user2",
		Value:    "admin2",
		HttpOnly: true,
	}

	//将cookie发送给浏览器
	//w.Header().Set("Set-Cookie", cookie.String())
	//添加第二个cookie
	//w.Header().Add("Ser-Cookie", cookie2.String())
	//直接调用HTTP的setcookie函数设置cookie
	http.SetCookie(w,&cookie)
	http.SetCookie(w,&cookie2)
}

//获取cookie
func getCookies(w http.ResponseWriter,r *http.Request){
	//获取请求头中所有的cookie
	//cookies := r.Header["Cookie"]
	//得到某一个cookie
	cookie,_ := r.Cookie("user")
	fmt.Println("得到的Cookie有:",cookie)
}

func main(){
	http.HandleFunc("/setCookie",setCookie)
	http.HandleFunc("/getCookies",getCookies)
	http.ListenAndServe(":8080",nil)
}

Session

  • 使用 Cookie 有一个非常大的局限,就是如果 Cookie 很多,则无形的增加了客户端与服务端的数据传输量。而且由于浏览器对 Cookie 数量的限制,不能再Cookie 中保存过多的信息
  • Session 的作用就是在服务器端保存一些用户的数据,然后传递给用户一个特殊的 Cookie,这个 Cookie 对应着这个服务器中的一个 Session,通过它就可以获取到保存用户信息的 Session,进而就知道是哪个用户再发送请求。
Session 的运行原理
  • 第一次向服务器发送请求时创建 Session,给它设置一个全球唯一的 ID(可以通过UUID 生成)

  • 创建一个 Cookie,将 Cookie 的 Value 设置为 Session 的 ID 值,并将 Cookie 发送给浏览器

  • 以后再发送请求浏览器就会携带着该 Cookie
    接调用HTTP的setcookie函数设置cookie
    http.SetCookie(w,&cookie)
    http.SetCookie(w,&cookie2)
    }

//获取cookie
func getCookies(w http.ResponseWriter,r *http.Request){
//获取请求头中所有的cookie
//cookies := r.Header[“Cookie”]
//得到某一个cookie
cookie,_ := r.Cookie(“user”)
fmt.Println(“得到的Cookie有:”,cookie)
}

func main(){
http.HandleFunc("/setCookie",setCookie)
http.HandleFunc("/getCookies",getCookies)
http.ListenAndServe(":8080",nil)
}


### Session

+ 使用 Cookie 有一个非常大的局限,就是如果 Cookie 很多,则无形的增加了客户端与服务端的数据传输量。而且由于浏览器对 Cookie 数量的限制,不能再Cookie 中保存过多的信息
+ Session 的作用就是**在服务器端保存一些用户的数据**,然后传递给用户一个特殊的 Cookie,这个 Cookie 对应着这个服务器中的一个 Session,通过它就可以获取到保存用户信息的 Session,进而就知道是哪个用户再发送请求。

##### Session 的运行原理

+ 第一次向服务器发送请求时创建 Session,给它设置一个全球唯一的 ID(可以通过UUID 生成)

+ 创建一个 Cookie,将 Cookie 的 Value 设置为 Session 的 ID 值,并将 Cookie 发送给浏览器
+ 以后再发送请求浏览器就会携带着该 Cookie
+ 服务器获取 Cookie 并根据它的 Value 值找到服务器中对应的 Session,也就知道了请求是哪个用户发的
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值