@[TOC]golang的net/http包练习笔记
简介
正在学习golang,这段时间研究了一下net/http包的使用,主要是client端的request发包,包括使用get/post/postform/do等方法,在此做一记录
package main
import (
"compress/gzip"
"fmt"
"io/ioutil"
"log"
"net/http"
"net/url"
"strconv"
"strings"
)
// var requestGetURLNoParams = "https://www.baidu.com"
var requestGetURLNoParams = "https://www.sohu.com"
// var requestGetURLWithParams = "https://https://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=1&rsv_idx=1&tn=monline_3_dg&wd=golang&fenlei=256&rsv_pq=0xfbdf6e810002e2fb&rsv_t=3cefAeXxNLf2ZS4%2FusXt41oP39aSEZ793S%2Fr%2FaNLReLNoNshrzHk1yC1mVfx&rqlang=en&rsv_dl=tb&rsv_enter=1&rsv_sug3=8&rsv_sug1=2&rsv_sug7=101&rsv_sug2=0&rsv_btype=t&inputT=920&rsv_sug4=1517"
// 基本get请求
func basicGet() {
resp, err := http.Get(requestGetURLNoParams)
if err != nil {
log.Println("err")
}
defer resp.Body.Close()
//在 Go 中 Http 请求的返回结果为 *http.Response 类型,Response.Body 类型为 io.Reader
//Response 结构体如下
/*
type Response struct {
Status string // e.g. "200 OK"
StatusCode int // e.g. 200
Proto string // e.g. "HTTP/1.0"
ProtoMajor int // e.g. 1
ProtoMinor int // e.g. 0
// Header将头键映射到值。
//如果响应有多个具有相同密钥的头,则可以使用逗号限制将它们串联起来。
//当此结构中的其他字段(如ContentLength、transferncode、Trailer)复制头值时,字段值是权威的。
Header Header
// Body代表响应体。
//响应主体在读取主体字段时按需流式传输。
//如果网络连接失败或服务器终止响应,Body.Read调用返回错误,http客户机和传输保证Body始终为非nil, 关闭响应体时调用者的责任
// 如果响应体未读到完成并关闭,则默认HTTP客户端的传输可能不会重用HTTP/1.x“keep alive”TCP连接
// 如果服务器用“chunked”传输编码答复,则响应体将自动取消dechunked
Body io.ReadCloser
// ContentLength记录关联内容的长度。值>=0表示可以从Body读取给定的字节数。
ContentLength int64
// 包含从最外层到最内层的传输编码。值为nil,表示使用“identity”编码。
TransferEncoding []string
//Close记录响应头是否指示在读取Body之后关闭连接(是为客户提供建议)
Close bool
// 报告响应是否已压缩发送,但已由http包解压缩
// 如果为true,则从Body读取生成未压缩的内容,而不是从服务器实际设置的压缩内容,ContentLength设置为-1,并且从responseHeader中删除“content Length”和“content Encoding”字段
// 一般是压缩方式,利用gzip压缩文档能够显著地减少HTML文档的下载时间。
Uncompressed bool
// 将Trailer 键映射到与标头相同格式的值,初始是nil,服务器的Trailer头值中,指定的每个键对应一个值
Trailer Header
// Request 请求是为获取此响应而发送的请求。请求的主体为零(已被消耗)这仅为客户端请求填充
Request *Request
// TLS包含有关接收响应的TLS连接的信息
TLS *tls.ConnectionState
}
*/
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Println("err")
}
fmt.Println(string(body))
}
// get请求参数放到 "net/url"
func basicGetURLParams() {
//调用net/url包
params := url.Values{}
//将url解析为一个结构体
parseURL, err := url.Parse(requestGetURLNoParams)
if err != nil {
log.Println("err")
}
params.Set("aaa", "aaa")
params.Set("age", "23")
//如果参数中有中文参数,这个方法会进行URLEncode
parseURL.RawQuery = params.Encode()
urlPathWithParams := parseURL.String()
resp, err := http.Get(urlPathWithParams)
if err != nil {
log.Println("err")
}
defer resp.Body.Close()
b, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Println("err")
}
fmt.Println(string(b))
}
func httpGetDo() {
//先生成http.client -> 再生成 http.request -> 之后提交请求:client.Do(request) -> 处理返回结果,每一步的过程都可以设置一些具体的参数
// 简式声明一个http.Client空结构体指针对象
client := &http.Client{}
// 使用http.NewRequest构建http Request请求
//func NewRequest(method, url string, body io.Reader) (*Request, error)
request, err := http.NewRequest("GET", requestGetURLNoParams, nil)
if err != nil {
log.Println("err")
}
// 使用http.Cookie结构体初始化一个cookie键值对
cookie := &http.Cookie{Name: "userId", Value: strconv.Itoa(12345)}
/*
// 另一种添加cookie的方法
cookie := &http.Cookie{
Name: "aaa",
Value: "aaa-value",
}
req.AddCookie(cookie1)
*/
// 使用前面构建的request方法AddCookie往请求中添加cookie
request.AddCookie(cookie)
// 设置request的Header,具体可参考http协议
request.Header.Set("Accept", "text/html, application/xhtml+xml, application/xml;q=0.9, */*;q=0.8")
request.Header.Set("Accept-Charset", "GBK, utf-8;q=0.7, *;q=0.3")
request.Header.Set("Accept-Encoding", "gzip, deflate, sdch")
request.Header.Set("Accept-Language", "zh-CN, zh;q=0.8")
request.Header.Set("Cache-Control", "max-age=0")
request.Header.Set("Connection", "keep-alive")
// 使用http.Client 来发送request,这里使用了Do方法。
response, err := client.Do(request)
if err != nil {
log.Println(err)
return
}
// 程序结束时关闭response.Body响应流
defer response.Body.Close()
// 接收到的http Response 状态值
fmt.Println(response.StatusCode)
if response.StatusCode == 200 { // 200意味成功得到http Server返回的http Response信息
// gzip.NewReader对压缩的返回信息解压(考虑网络传输量,http Server
// 一般都会对响应压缩后再返回)
body, err := gzip.NewReader(response.Body)
// body := response.Body
if err != nil {
log.Println(err)
}
defer body.Close()
r, err := ioutil.ReadAll(body)
if err != nil {
log.Println(err)
}
// 打印出http Server返回的http Response信息
log.Println(string(r))
}
}
func basicPost() {
//func (c *Client) Post(url string, bodyType string, body io.Reader) (resp *Response, err error)
/*
func NewReader(s string) *Reader {
return &Reader{s, 0, -1}
}
*/
/*
type Reader interface {
Read(p []byte) (n int, err error)
}
*/
resp, err := http.Post("http://localhost:8080/login.do",
"application/x-www-form-urlencoded", strings.NewReader("mobile=xxxxxxxxxx&isRemberPwd=1"))
if err != nil {
log.Println(err)
return
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Println(err)
return
}
fmt.Println(string(body))
}
func basicPostForm() {
//func (c *Client) PostForm(url string, data url.Values) (resp *Response, err error)
//PostForm向指定的URL发出一个POST请求,url.Values类型的data会被编码为请求的主体。
//POST数据的类型一般会设为"application/x-www-form-urlencoded"
postParam := url.Values{
"mobile": {"xxxxxx"},
"isRemberPwd": {"1"},
}
// 数据的键值会经过URL编码后作为请求的body传递
resp, err := http.PostForm("http://localhost:8080/login.do", postParam)
if err != nil {
log.Println(err)
return
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Println(err)
return
}
fmt.Println(string(body))
}
func main() {
//Get方法
basicGet()
//get with params
basicGetURLParams()
//Post方法
basicPost()
//Postform方法
basicPostForm()
//http.do
httpGetDo()
}