前言:大家好,以下所有内容都是我学习韩茹老师的教程时所整理的笔记。部分内容有过删改, 推荐大家去看原作者的文档进行学习, 本文章仅作为个人的学习笔记,后续还会在此基础上不断修改。学习Go Web时应该已经熟悉Go语言基本语法以及计算机网络的相关内容。
学习链接:https://www.chaindesk.cn/witbook/17/253
参考书籍:《Go Web编程实战派》
在上节课我们通过搭建一个简单的Go Web服务器,已经了解过http包。下面就介绍下如何通过http协议去请求。
go语言中提供了net/http库去进行网络请求,我们在import中需要导入我们用到的库。
net/http,和html/template这两个标准库,是实现Go Web最核心的。net/http标准库可以分为客户端和服务器两个部分,库中的结构和函数,有些只支持客户端和服务器这两者中的一个,而有些则同时支持客户端和服务器:
下面来看一个简单的get实现,创建项目,新建一个go文件(demo01_client.go):
package main import ( "net/http" "fmt" ) func main() { requestUrl := "www.baidu.com" //requestUrl := "http://www.baidu.com" response, err := http.Get(requestUrl) if err != nil { fmt.Println("err:", err) } defer response.Body.Close() fmt.Println(response.Body) }
然后就报错了:err: Get www.baidu.com: unsupported protocol scheme “”
错误:不支持scheme为空的协议,这是什么情况呢,
requestUrl改为requestUrl := "http://www.baidu.com"
scheme反应出的就是协议名称。
重新运行程序,可以正常执行了,运行结果:
&{[] 0xc0000a6080 <nil> <nil>}
response中的参数一般也比较多,我们需要的最多的通常是Body参数,Body是 io.ReadCloser 这个类型的对象。用 ioutil.ReadAll 去转化 io.ReadCloser 类型,输出是 byty[](补充:这里应该是 byte[]
),再通过string()强制转换就能看到string了。
if response.StatusCode == 200 { r, err := ioutil.ReadAll(response.Body) if err != nil { fmt.Println(err) } return string(r) }
正确获取到了服务器响应的数据才能这么打印出来了,假如失败了呢,因此需要判断返回码,再去获取body的数据。
最后要记得关闭。
demo02_response.go的详细代码:
package main import ( "net/http" "log" "fmt" "io/ioutil" ) func main() { urlStr := "http://www.webxml.com.cn/WebServices/WeatherWebService.asmx/getWeatherbyCityName?theCityName=北京" response, err := http.Get(urlStr) if err != nil { log.Fatal(err) } defer response.Body.Close() if response.StatusCode == 200 { body, err := ioutil.ReadAll(response.Body) if err != nil { log.Fatal(err) } fmt.Println(string(body)) } fmt.Println("-----------------------------------------") fmt.Printf("response:%+v\n", response) fmt.Println("-----------------------------------------") fmt.Printf("response.Body:%+v\n", response.Body) fmt.Printf("response.Header:%+v\n", response.Header) fmt.Printf("response.StatusCode:%+v\n", response.StatusCode) fmt.Printf("response.Status:%+v\n", response.Status) fmt.Printf("response.Request:%+v\n", response.Request) fmt.Printf("response.Cookies:%+v\n", response.Cookies()) }
运行结果:
<?xml version="1.0" encoding="utf-8"?> <ArrayOfString xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://WebXml.com.cn/"> <string>直辖市</string> <string>北京</string> <string>54511</string> <string>54511.jpg</string> <string>2021/11/20 21:19:15</string> <string>0℃/10℃</string> <string>11月20日 多云</string> <string>北风转南风小于3级</string> <string>1.gif</string> <string>1.gif</string> <string>今日天气实况:气温:5℃;风向/风力:南风 1级;湿度:65%;紫外线强度:弱。</string> <string>感冒指数:少发,无明显降温,感冒机率较低。 运动指数:较适宜,气温较低,在户外运动请注意增减衣物。 过敏指数:极不易发,无需担心过敏,可放心外出,享受生活。 穿衣指数:较冷,建议着厚外套加毛衣等服装。 洗车指数:适宜,天气较好,适合擦洗汽车。 紫外线指数:弱,辐射较弱,涂擦SPF12-15、PA+护肤品。 </string> <string>-2℃/8℃</string> <string>11月21日 多云</string> <string>西北风4-5级</string> <string>1.gif</string> <string>1.gif</string> <string>-5℃/4℃</string> <string>11月22日 晴</string> <string>西北风4-5级转西风小于3级</string> <string>0.gif</string> <string>0.gif</string> <string>北京位于华北平原西北边缘,市中心位于北纬39度,东经116度,四周被河北省围着,东南和天津市相接。全市面积一万六千多平方公里,辖12区6县,人口1100余万。北京为暖温带半湿润大陆性季风气候,夏季炎热多雨,冬季寒冷干燥,春、秋短促,年平均气温10-12摄氏度。北京是世界历史文化名城和古都之一。早在七十万年前,北京周口店地区就出现了原始人群部落“北京人”。而北京建城也已有两千多年的历史,最初见于记载的名字为“蓟”。公元前1045年北京成为蓟、燕等诸侯国的都城;公元前221年秦始皇统一中国以来,北京一直是中国北方重镇和地方中心;自公元938年以来,北京又先后成为辽陪都、金上都、元大都、明清国都。1949年10月1日正式定为中华人民共和国首都。北京具有丰富的旅游资源,对外开放的旅游景点达200多处,有世界上最大的皇宫紫禁城、祭天神庙天坛、皇家花园北海、皇家园林颐和园,还有八达岭、慕田峪、司马台长城以及世界上最大的四合院恭王府等各胜古迹。全市共有文物古迹7309项,其中国家文物保护单位42个,市级文物保护单位222个。北京的市树为国槐和侧柏,市花为月季和菊花。另外,北京出产的象牙雕刻、玉器雕刻、景泰蓝、地毯等传统手工艺品驰誉世界。</string> </ArrayOfString> ------------------------- response: &{Status:200 OK StatusCode:200 Proto:HTTP/1.1 ProtoMajor:1 ProtoMinor:1 Header:map[Cache-Control:[private, max-age=0] Content-Type:[text/xml; charset=utf-8] Date:[Sat, 20 Nov 2021 13:22:37 GMT] Server:[Microsoft-IIS/7.5] Vary:[Accept-Encoding] X-Aspnet-Version:[2.0.50727] X-Powered-By:[ASP.NET]] Body:0xc000048060 ContentLength:-1 TransferEncoding:[] Close:false Uncompressed:true Trailer:map[] Request:0xc000114000 TLS:<nil>} ------------------------- response.Body: &{_:[] body:0xc000026080 zr:0xc00004c2c0 zerr:<nil>} response.Header: map[Cache-Control:[private, max-age=0] Content-Type:[text/xml; charset=utf-8] Date:[Sat, 20 Nov 2021 13:22:37 GMT] Server:[Microsoft-IIS/7.5] Vary:[Accept-Encoding] X-Aspnet-Version:[2.0.50727] X-Powered-By:[ASP.NET]] response.StatusCode: 200 response.Status: 200 OK response.Request: &{Method:GET URL:http://www.webxml.com.cn/WebServices/WeatherWebService.asmx/getWeatherbyCityName?theCityName=北京 Proto:HTTP/1.1 ProtoMajor:1 ProtoMinor:1 Header:map[] Body:<nil> GetBody:<nil> ContentLength:0 TransferEncoding:[] Close:false Host:www.webxml.com.cn Form:map[] PostForm:map[] MultipartForm:<nil> Trailer:map[] RemoteAddr: RequestURI: TLS:<nil> Cancel:<nil> Response:<nil> ctx:0xc0000ba058} response.Cookies: []
浏览器直接打开网页效果如下:
go语言的客户端有几种实现方式。
先生成 http.client -> 再生成 http.request -> 之后提交请求:client.Do(request) -> 处理返回结果,每一步的过程都可以设置一些具体的参数。
新建go文件(demo03_NewRequest.go),示例代码如下:
package main import ( "net/http" "log" "fmt" "io/ioutil" ) func main() { /** 客户端实现方式一: 1.先生成 http.client -> 2.再生成 http.request -> 3.之后提交请求:client.Do(request) -> 4.处理返回结果,每一步的过程都可以设置一些具体的参数。 */ urlStr := "http://www.webxml.com.cn/WebServices/WeatherWebService.asmx/getWeatherbyCityName?theCityName=北京" //step1:创建client对象 client := http.Client{} //step2:创建request request, err := http.NewRequest("GET", urlStr, nil) if err != nil { log.Fatal(err) } //step3:发送请求 response, err := client.Do(request) if err != nil { log.Fatal(err) } defer response.Body.Close() if response.StatusCode == 200 { body, err := ioutil.ReadAll(response.Body) if err != nil { log.Fatal(err) } fmt.Println(string(body)) } fmt.Println("-----------------------------------------") fmt.Printf("response:%+v\n", response) fmt.Println("-----------------------------------------") fmt.Printf("response.Body:%+v\n", response.Body) fmt.Printf("response.Header:%+v\n", response.Header) fmt.Printf("response.StatusCode:%+v\n", response.StatusCode) fmt.Printf("response.Status:%+v\n", response.Status) fmt.Printf("response.Request:%+v\n", response.Request) fmt.Printf("response.Cookies:%+v\n", response.Cookies()) }
也可以使用默认的DefaultClient对象。
新建go文件(demo04_defaultclient.go),实例代码如下:
package main import ( "net/http" "net/http/httputil" "fmt" ) func main() { request, err := http.NewRequest(http.MethodGet, "http://www.chaindesk.cn/", nil) request.Header.Add("User-Agent", "Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1") resp, err := http.DefaultClient.Do(request) //resp, err := http.Get("http://www.chaindesk.cn/") //resp, err := http.Get("http://www.baidu.com/") if err != nil { panic(err) } defer resp.Body.Close() s, err := httputil.DumpResponse(resp, true) if err != nil{ panic(err) } fmt.Printf("%s\n", s) }
先生成client,之后用 client.get/post…
client 结构自己也有一些发送 api 的方法,比如 client.get, client.post, client.postform… 等等。基本上涵盖了主要的http请求的类型,通常不进行什么特殊的配置的话,这样就可以了,其实client的 get 或者 post 方法,也是对 http.Newerequest 方法的封装,里面还额外添加了 req.Header.Set(“Content-Type”, bodyType) 一般用的话,也是 ok 的。
新建go文件(demo05_client_get.go),示例代码:
package main import ( "net/http" "log" "fmt" "io/ioutil" ) func main() { /** 方式二 调用client的API 1.先生成client, 2.之后用client.get/post.. 还额外添加了req.Header.Set("Content-Type", bodyType)... */ urlStr := "http://www.webxml.com.cn/WebServices/WeatherWebService.asmx/getWeatherbyCityName?theCityName=北京" //step1:创建client对象 client := http.Client{} //step2:调用get方法,发送请求 response, err := client.Get(urlStr) if err != nil { log.Fatal(err) } defer response.Body.Close() if response.StatusCode == 200 { body, err := ioutil.ReadAll(response.Body) if err != nil { log.Fatal(err) } fmt.Println(string(body)) } fmt.Printf("%+v", response) }
可以通过之前的方式,先创建client对象,然后调用 client.Get(url) 方法,或者是 client.Post(url, contentType, body) 实现get或post的请求。也可以通过http直接进行调用。
golang的标准api中用于http客户端请求的主要有三个api : http.Get
,http.Post
,http.PostForm
,其区别如下:
API | 特点 |
---|---|
http.Get | 发送get请求 |
http.Post | post请求提交指定类型的数据 |
http.PostForm | post请求提交 application/x-www-form-urlencoded 数据 |
在使用http客户端api的时候要注意一个问题:请求地址的url必须是带http://协议头的完整url, 不然请求结果为空。
http包中Get()方法的源代码:
func Get(url string) (resp *Response, err error) { return DefaultClient.Get(url) }
新建go文件(demo06_http_get.go),示例代码:
package main import ( "net/http" "fmt" "io/ioutil" "log" ) func main() { resp, err := http.Get("http://www.baidu.com") if err != nil { // handle error log.Fatal(err) } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { // handle error log.Fatal(err) } fmt.Println(string(body)) }
post请求可以通过client对象调用 Post() 方法,也可以通过http直接进行调用。
client对象的 Post() 方法源代码:
func (c *Client) Post(url string, contentType string, body io.Reader) (resp *Response, err error) { req, err := NewRequest("POST", url, body) if err != nil { return nil, err } req.Header.Set("Content-Type", contentType) return c.Do(req) }
新建go文件(demo07_client_post.go),示例代码:
package main import ( "net/http" "log" "fmt" "io/ioutil" "bytes" "net/url" ) func main() { urlStr := "http://www.webxml.com.cn/WebServices/WeatherWebService.asmx/getWeatherbyCityName" client := http.Client{} param := &url.Values{ "theCityName": {"苏州"}, } requestBody := bytes.NewBufferString(param.Encode()) response, err := client.Post(urlStr, "application/x-www-form-urlencoded", requestBody) if err != nil { log.Fatal(err) } defer response.Body.Close() if response.StatusCode == 200 { body, err := ioutil.ReadAll(response.Body) if err != nil { log.Fatal(err) } fmt.Println(string(body)) } fmt.Printf("%+v", response) }
也可以通过http包的Post()直接实现,源代码如下:
func Post(url string, contentType string, body io.Reader) (resp *Response, err error) { return DefaultClient.Post(url, contentType, body) }
新建go文件(demo08_http_post.go),示例代码:
package main import ( "net/http" "strings" "io/ioutil" "fmt" ) func main() { resp, err := http.Post("http://www.webxml.com.cn/WebServices/WeatherWebService.asmx/getWeatherbyCityName", "application/x-www-form-urlencoded", strings.NewReader("theCityName=苏州")) if err != nil { fmt.Println(err) } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { // handle error } fmt.Println(string(body)) }
注意:使用post方法,要设置contentType
,设置成 “application/x-www-form-urlencoded”,否则post参数无法传递。
也可以自己搭建服务器:
新建go文件(demo09_post.go),客户端代码:
package main import ( "net/http" "net/url" "io/ioutil" "fmt" "bytes" "log" ) func main() { /** 也可以使用自己搭建的服务器 */ urlStr := "http://localhost:2001/login" param := url.Values{ "username": {"嘘嘘嘘大学"}, "password": {"ClimberCoding12121"}, } requestBody := bytes.NewBufferString(param.Encode()) response, err := http.Post(urlStr, "application/x-www-form-urlencoded", requestBody) if err != nil { log.Fatal(err) } defer response.Body.Close() if response.StatusCode == 200 { body, err := ioutil.ReadAll(response.Body) if err != nil { log.Fatal(err) } fmt.Println(string(body)) } fmt.Printf("response: %+v\n", response) fmt.Printf("response.Header: %+v\n", response.Header) fmt.Printf("response.Cookies: %+v\n", response.Cookies()) }
新建go文件(demo09_server.go),服务器端代码:
package main import ( "net/http" "io/ioutil" "log" "fmt" "io" ) func main() { server := http.NewServeMux() //路由 server.HandleFunc("/login", login) http.ListenAndServe(":2001", server) } func login(w http.ResponseWriter, r *http.Request) { r.ParseForm() body, err := ioutil.ReadAll(r.Body) r.Body.Close() if err != nil { log.Fatal(err) } fmt.Println("body", string(body)) fmt.Printf("r: %+v\n", r) fmt.Printf("%+v\n", r.Header) fmt.Printf("%+v\n", r.Header["Content-Type"]) fmt.Printf("%+v\n", r.Cookies()) if len(r.Form["username"]) > 0 { username := r.Form["username"][0] fmt.Println("username: ", username) } if len(r.Form["password"]) > 0 { password := r.Form["password"][0] fmt.Println("password: ", password) } io.WriteString(w, "登录成功") }
先启动服务端,再启动客户端,
服务端运行结果:
body r: &{Method:POST URL:/login Proto:HTTP/1.1 ProtoMajor:1 ProtoMinor:1 Header:map[Accept-Encoding:[gzip] Content-Length:[82] Content-Type:[application/x-www-form-urlencoded] User-Agent:[Go-http-client/1.1]] Body:0xc000026140 GetBody:<nil> ContentLength:82 TransferEncoding:[] Close:false Host:localhost:2001 Form:map[password:[ClimberCoding12121] username:[嘘嘘嘘大学]] PostForm:map[password:[ClimberCoding12121] username:[嘘嘘嘘大学]] MultipartForm:<nil> Trailer:map[] RemoteAddr:[::1]:54243 RequestURI:/login TLS:<nil> Cancel:<nil> Response:<nil> ctx:0xc000026180} map[Accept-Encoding:[gzip] Content-Length:[82] Content-Type:[application/x-www-form-urlencoded] User-Agent:[Go-http-client/1.1]] [application/x-www-form-urlencoded] [] username: 嘘嘘嘘大学 password: ClimberCoding12121
客户端运行结果:
登录成功 response: &{Status:200 OK StatusCode:200 Proto:HTTP/1.1 ProtoMajor:1 ProtoMinor:1 Header:map[Content-Length:[12] Content-Type:[text/plain; charset=utf-8] Date:[Sat, 20 Nov 2021 14:44:24 GMT]] Body:0xc000198040 ContentLength:12 TransferEncoding:[] Close:false Uncompressed:false Trailer:map[] Request:0xc000136000 TLS:<nil>} response.Header: map[Content-Length:[12] Content-Type:[text/plain; charset=utf-8] Date:[Sat, 20 Nov 2021 14:44:24 GMT]] response.Cookies: []
http包下的PostForm()方法源代码:
func PostForm(url string, data url.Values) (resp *Response, err error) { return DefaultClient.PostForm(url, data) }
新建go文件(demo10_postform.go),客户端实例代码:
package main import ( "net/http" "net/url" "io/ioutil" "fmt" "log" ) func main() { /** 还是使用上一个服务器 使用http.PostForm() */ response, err := http.PostForm("http://localhost:2001/login", url.Values{"username": {"嘘嘘嘘大学"}, "password": {"ClimberCoding12345"}}) if err != nil { log.Fatal(err) } defer response.Body.Close() if response.StatusCode == 200 { body, err := ioutil.ReadAll(response.Body) if err != nil { log.Fatal(err) } fmt.Println(string(body)) } fmt.Printf("response: %+v\n", response) fmt.Printf("response.Header: %+v\n", response.Header) fmt.Printf("response.Cookies: %+v\n", response.Cookies()) }
服务器端继续使用上次的代码,不用改动。
服务器端运行结果:
body r: &{Method:POST URL:/login Proto:HTTP/1.1 ProtoMajor:1 ProtoMinor:1 Header:map[Accept-Encoding:[gzip] Content-Length:[82] Content-Type:[application/x-www-form-urlencoded] User-Agent:[Go-http-client/1.1]] Body:0xc00008a0c0 GetBody:<nil> ContentLength:82 TransferEncoding:[] Close:false Host:localhost:2001 Form:map[password:[ClimberCoding12345] username:[嘘嘘嘘大学]] PostForm:map[password:[ClimberCoding12345] username:[嘘嘘嘘大学]] MultipartForm:<nil> Trailer:map[] RemoteAddr:[::1]:54327 RequestURI:/login TLS:<nil> Cancel:<nil> Response:<nil> ctx:0xc00008a100} map[Accept-Encoding:[gzip] Content-Length:[82] Content-Type:[application/x-www-form-urlencoded] User-Agent:[Go-http-client/1.1]] [application/x-www-form-urlencoded] [] username: 嘘嘘嘘大学 password: ClimberCoding12345
客户端运行结果:
登录成功 response: &{Status:200 OK StatusCode:200 Proto:HTTP/1.1 ProtoMajor:1 ProtoMinor:1 Header:map[Content-Length:[12] Content-Type:[text/plain; charset=utf-8] Date:[Sat, 20 Nov 2021 14:49:53 GMT]] Body:0xc00020c040 ContentLength:12 TransferEncoding:[] Close:false Uncompressed:false Trailer:map[] Request:0xc000136000 TLS:<nil>} response.Header: map[Content-Length:[12] Content-Type:[text/plain; charset=utf-8] Date:[Sat, 20 Nov 2021 14:49:53 GMT]] response.Cookies: []
有时需要在请求的时候设置头参数、cookie之类的数据,需要使用http.Do方法。
设置请求头:
request.Header.Set("Content-Type", "application/x-www-form-urlencoded")
Set()方法源代码:
func (h Header) Set(key, value string) { textproto.MIMEHeader(h).Set(key, value) }
设置Cookie:
方式一:通过设置请求头
request.Header.Set("Cookie", "name=hanru")
方式二:通过request对象,直接调用AddCookie()方法。
func (r *Request) AddCookie(c *Cookie) { s := fmt.Sprintf("%s=%s", sanitizeCookieName(c.Name), sanitizeCookieValue(c.Value)) if c := r.Header.Get("Cookie"); c != "" { r.Header.Set("Cookie", c+"; "+s) } else { r.Header.Set("Cookie", s) } }
新建go文件(demo11_client.go),客户端实例代码:
package main import ( "bytes" "fmt" "io/ioutil" "log" "net/http" "net/url" ) func main() { urlStr := "http://localhost:2000/login" client := http.Client{} param := url.Values{ "username": {"ClimberCoding"}, } //jsonStr, _ := json.Marshal(param) //requestBody := bytes.NewBufferString(string(jsonStr)) requestBody := bytes.NewBufferString(param.Encode()) request, err := http.NewRequest("POST", urlStr, requestBody) if err != nil { log.Fatal(err) } /* cookie的添加 方式一: request.Header.Set("Cookie", "name=ClimberCoding") 方式二: request.AddCookie(Cookie) */ cookId := &http.Cookie{Name: "userId", Value: "1234"} cookName := &http.Cookie{Name: "name", Value: "xuxuxudaxue"} request.AddCookie(cookId) request.AddCookie(cookName) //使用text/html就会出错 //application/x-www-form-urlencoded request.Header.Set("Content-Type", "application/x-www-form-urlencoded") response, err := client.Do(request) if err != nil { log.Fatal(err) } defer response.Body.Close() if response.StatusCode == 200 { body, err := ioutil.ReadAll(response.Body) if err != nil { log.Fatal(err) } fmt.Println(string(body)) } fmt.Printf("response: %+v\n", response) fmt.Printf("response.Header: %+v\n", response.Header) fmt.Printf("response.Cookies: %+v\n", response.Cookies()) fmt.Printf("request.Header: %+v\n", request.Header) fmt.Printf("request.Cookies: %+v\n", request.Cookies()) }
新建go文件(demo12_server.go),服务器端代码:
package main import ( "log" "net/http" "io" "io/ioutil" "fmt" ) func HandleRequest(w http.ResponseWriter, r *http.Request) { r.ParseForm() body, err := ioutil.ReadAll(r.Body) r.Body.Close() if err != nil { log.Fatal(err) } fmt.Println("body", string(body)) fmt.Printf("r: %+v\n", r) fmt.Printf("Request:Header:%+v\n", r.Header) fmt.Printf("cookies: %+v\n", r.Cookies()) cookid, err := r.Cookie("userId") if err == nil { fmt.Println(cookid.Name, cookid.Value) } if len(r.Form["username"]) > 0 { username := r.Form["username"][0] fmt.Println("username:", username) } w.Header().Set("Access-Control-Allow-Origin", "*") w.Header().Set("Access-Control-Allow-Headers", "*") io.WriteString(w, "login success ....") } func main() { http.HandleFunc("/login", HandleRequest) err := http.ListenAndServe(":2000", nil) if err != nil { log.Fatal(err) } }
服务器运行结果:
body r: &{Method:POST URL:/login Proto:HTTP/1.1 ProtoMajor:1 ProtoMinor:1 Header:map[Accept-Encoding:[gzip] Content-Length:[22] Content-Type:[application/x-www-form-urlencoded] Cookie:[userId=1234; name=xuxuxudaxue] User-Agent:[Go-http-client/1.1]] Body:0xc00008a0c0 GetBody:<nil> ContentLength:22 TransferEncoding:[] Close:false Host:localhost:2000 Form:map[username:[ClimberCoding]] PostForm:map[username:[ClimberCoding]] MultipartForm:<nil> Trailer:map[] RemoteAddr:[::1]:54385 RequestURI:/login TLS:<nil> Cancel:<nil> Response:<nil> ctx:0xc00008a100} Request:Header:map[Accept-Encoding:[gzip] Content-Length:[22] Content-Type:[application/x-www-form-urlencoded] Cookie:[userId=1234; name=xuxuxudaxue] User-Agent:[Go-http-client/1.1]] cookies: [userId=1234 name=xuxuxudaxue] userId 1234 username: ClimberCoding
客户端运行结果:
login success .... response: &{Status:200 OK StatusCode:200 Proto:HTTP/1.1 ProtoMajor:1 ProtoMinor:1 Header:map[Access-Control-Allow-Headers:[*] Access-Control-Allow-Origin:[*] Content-Length:[18] Content-Type:[text/plain; charset=utf-8] Date:[Sat, 20 Nov 2021 14:54:37 GMT]] Body:0xc00020e040 ContentLength:18 TransferEncoding:[] Close:false Uncompressed:false Trailer:map[] Request:0xc000136000 TLS:<nil>} response.Header: map[Access-Control-Allow-Headers:[*] Access-Control-Allow-Origin:[*] Content-Length:[18] Content-Type:[text/plain; charset=utf-8] Date:[Sat, 20 Nov 2021 14:54:37 GMT]] response.Cookies: [] request.Header: map[Content-Type:[application/x-www-form-urlencoded] Cookie:[userId=1234; name=xuxuxudaxue]] request.Cookies: [userId=1234 name=xuxuxudaxue]
如果要发起head请求可以直接使用http client的head方法,比较简单,这里就不再说明。
源代码