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,也就知道了请求是哪个用户发的