go语言内置的net/http包十分优秀,提供了http客户端和服务器的实现。
超文本传输协议(http,hypertext transfer protocol)是互联网上应用最为广泛的一种网络传输协议,所有的www文件都必须遵循这个标准。设计http最初的目的是为了提供一种发布和接收html页面的方法。
一. http客户端
基本的http/https请求get,head,post和postform函数发出http/https请求。
resp, err := http.get("http://example.com") //... resp, err = http.post("http://example.com", "image/jpeg", &buf) //... resp, err = http.postform("http://example.com", url.values{"key": {"value"}, "id": {"123"}})
程序在使用完response后必须关闭回复的主体。
package main import ( "io/ioutil" "log" "net/http" ) func main() { resp, err := http.get("http://example.com") if err != nil { log.println("http get fail") return } //关闭回复主体 defer resp.body.close() body, err := ioutil.readall(resp.body) //... }
1.1 get请求
函数签名:
func get(url string) (resp *response, err error)
get向指定的url发出get请求,如果回应的状态码如下,get会调用c.checkredirect后执行重定向。
- 301(moved permanently)
- 302(found)
- 303(see other)
- 307(temporary redirect)
如果c.checkredirect执行失败或存在http协议错误时,本方法返回错误。如果回应的状态码不是2xx,本方法并不会返回错误。如果返回值err为nil,resp.body总是非nil的,调用者应该在读取完resp.body后关闭它。
get是对defaultclient的get方法的包装。
1.2 post和get示例服务端代码
package main import ( "fmt" "io/ioutil" "net/http" ) func gethandlefunc(w http.responsewriter, r *http.request) { defer r.body.close() data := r.url.query() //获得get方法的参数 fmt.println(data.get("name")) fmt.println(data.get("age")) answer := `{"status":"ok"}` w.write([]byte(answer)) } func posthandlefunc(w http.responsewriter, r *http.request) { defer r.body.close() //请求数据类型是application/json b, err := ioutil.readall(r.body) if err != nil { fmt.println("read request body fail ", err) return } fmt.println(string(b)) answer := `{"statue":"ok"}` w.write([]byte(answer)) } func handlefunc(w http.responsewriter, r *http.request) { fmt.println("get a link....") switch r.method { case http.methodget: http.handlefunc("/get", gethandlefunc) case http.methodpost: http.handlefunc("/post", posthandlefunc) } } func main() { http.handlefunc("/", handlefunc) err := http.listenandserve(":9090", nil) if err != nil { fmt.println("http server fail ", err) return } }
1.3 get方法示例
不带参数客户端
package main import ( "fmt" "io/ioutil" "log" "net/http" ) func main() { resp, err := http.get("https://www.baidu.com") if err != nil { log.println("http get fail ", err) return } //关闭回复主体 defer resp.body.close() body, err := ioutil.readall(resp.body) if err != nil { log.println("read resp body fail ", err) return } fmt.print(string(body)) }
带参数客户端
关于get请求带参数需要使用go语言内置的net/url标准库来处理。
package main import ( "fmt" "io/ioutil" "net/http" "net/url" ) func main() { apiurl := "http://127.0.0.1:9090/get" //url参数 data := url.values{} data.set("name", "张三") data.set("age", "20") //url参数需要编码,因为有的特殊字符被赋予了特殊含义 u, err := url.parserequesturi(apiurl) if err != nil { fmt.println("url parse fail ", err) } u.rawquery = data.encode() //url encode fmt.println(u.string()) resp, err := http.get(u.string()) if err != nil { fmt.printf("url %v get fail %v", u.string(), err) return } defer resp.body.close() b, err := ioutil.readall(resp.body) if err != nil { fmt.println("read body fail ", err) return } fmt.println(string(b)) }
1.4 post请求
函数签名:
func post(url string, bodytype string, body io.reader) (resp *response, err error)
post向指定的url发送一个post请求。bodytype为post的数据类型,body为post数据,作为请求的主体。如果参数body实现了io.closer接口,它会在发送请求后被关闭。调用者有责任在读取完返回值resp的主体后关闭它。
post是对包变量defaultclient的post方法的包装。
1.5 post示例
package main import ( "fmt" "io/ioutil" "net/http" "strings" ) func main() { apiurl := "http://127.0.0.1:9090/post" //表单数据 contenttype := "application/json" data := `{"name":"张三", "age":18}` resp, err := http.post(apiurl, contenttype, strings.newreader(data)) if err != nil { fmt.printf("url : %v post fail err : %v\n", apiurl, err) return } defer resp.body.close() b, err := ioutil.readall(resp.body) if err != nil { fmt.println("read body err ", err) return } fmt.println(string(b)) }
1.6 自定义client
要管理http客户端头域,重定向和其它策略,创建一个client:
type client struct { // transport指定执行独立、单次http请求的机制。 // 如果transport为nil,则使用defaulttransport。 transport roundtripper // checkredirect指定处理重定向的策略。 // 如果checkredirect不为nil,客户端会在执行重定向之前调用本函数字段。 // 参数req和via是将要执行的请求和已经执行的请求(切片,越新的请求越靠后)。 // 如果checkredirect返回一个错误,本类型的get方法不会发送请求req, // 而是返回之前得到的最后一个回复和该错误。(包装进url.error类型里) // // 如果checkredirect为nil,会采用默认策略:连续10此请求后停止。 checkredirect func(req *request, via []*request) error // jar指定cookie管理器。 // 如果jar为nil,请求中不会发送cookie,回复中的cookie会被忽略。 jar cookiejar // timeout指定本类型的值执行请求的时间限制。 // 该超时限制包括连接时间、重定向和读取回复主体的时间。 // 计时器会在head、get、post或do方法返回后继续运作并在超时后中断回复主体的读取。 // // timeout为零值表示不设置超时。 // // client实例的transport字段必须支持cancelrequest方法, // 否则client会在试图用head、get、post或do方法执行请求时返回错误。 // 本类型的transport字段默认值(defaulttransport)支持cancelrequest方法。 timeout time.duration }
client类型代表http客户端。它的零值(defaultclient)是一个可用的使用defaulttransport的客户端。
client的transport字段一般会含有内部状态(缓存tcp连接),因此client类型值应尽量被重用而不是每次需要都创建新的。client类型值可以安全的被多个go程同时使用。
client类型的层次比roundtripper接口(如transport)高,还会管理http的cookie和重定向等细节。
//设置重定向 client := &http.client{ checkredirect : redirectpolicyfunc, } resp, err := client.get("http://example.com") //... //加请求头部 req, err := http.newrequest("get", "http://example.com", nil) //... req.header.add("if-none-match", `w/"wyzzy"`) resp, err := client.do(req) //...
1.7 自定义transport
go语言中的http.transport是一个高性能的http客户端库,它提供了连接池、重试、超时控制等功能,可以方便地进行 http 请求。
要管理代理,tls配置,keep-alive,压缩和其它设置,可以创建一个transport,对应client的transport字段。
type transport struct { // proxy指定一个对给定请求返回代理的函数。 // 如果该函数返回了非nil的错误值,请求的执行就会中断并返回该错误。 // 如果proxy为nil或返回nil的*url置,将不使用代理。 proxy func(*request) (*url.url, error) // dial指定创建tcp连接的拨号函数。如果dial为nil,会使用net.dial。 dial func(network, addr string) (net.conn, error) // tlsclientconfig指定用于tls.client的tls配置信息。 // 如果该字段为nil,会使用默认的配置信息。 tlsclientconfig *tls.config // tlshandshaketimeout指定等待tls握手完成的最长时间。零值表示不设置超时。 tlshandshaketimeout time.duration // 如果disablekeepalives为真,会禁止不同http请求之间tcp连接的重用。 disablekeepalives bool // 如果disablecompression为真,会禁止transport在请求中没有accept-encoding头时, // 主动添加"accept-encoding: gzip"头,以获取压缩数据。 // 如果transport自己请求gzip并得到了压缩后的回复,它会主动解压缩回复的主体。 // 但如果用户显式的请求gzip压缩数据,transport是不会主动解压缩的。 disablecompression bool // 如果maxidleconnsperhost!=0,会控制每个主机下的最大闲置连接。 // 如果maxidleconnsperhost==0,会使用defaultmaxidleconnsperhost。 maxidleconnsperhost int // responseheadertimeout指定在发送完请求(包括其可能的主体)之后, // 等待接收服务端的回复的头域的最大时间。零值表示不设置超时。 // 该时间不包括获取回复主体的时间。 responseheadertimeout time.duration // 内含隐藏或非导出字段 }
tr := &http.transport{ tlsclientconfig: &tls.config{ rootcas: pool, }, disablecompression: true, } client := &http.client{ transport: tr, } resp, err := client.get("http://example.com") //...
二. 服务端
2.1 默认server
listenandserver使用指定的监听地址和处理器启动一个http服务端。处理器参数通常是nil,这表示采用包变量defaultservemux作为处理器。
handle和handlefunc函数可以向defaultservemux添加处理器。
http.handle("/foo", foohandler) http.handlefunc("/hello", func(w http.responsewriter, r *http.request) { fmt.fprintf(w, "hello %q", html.escapestring(r.url.path)) }) log.fatal(http.listenandserve(":8080", nil))
2.2 示例
package main import ( "fmt" "net/http" ) func sayhello(w http.responsewriter, r *http.request) { defer r.body.close() fmt.fprintln(w, "hello 张三") } func main() { http.handlefunc("/", sayhello) err := http.listenandserve(":8080", nil) if err != nil { fmt.println("http server fail, err ", err) return } }
2.3 自定义server
type server struct { addr string // 监听的tcp地址,如果为空字符串会使用":http" handler handler // 调用的处理器,如为nil会调用http.defaultservemux readtimeout time.duration // 请求的读取操作在超时前的最大持续时间 writetimeout time.duration // 回复的写入操作在超时前的最大持续时间 maxheaderbytes int // 请求的头域最大长度,如为0则用defaultmaxheaderbytes tlsconfig *tls.config // 可选的tls配置,用于listenandservetls方法 // tlsnextproto(可选地)指定一个函数来在一个npn型协议升级出现时接管tls连接的所有权。 // 映射的键为商谈的协议名;映射的值为函数,该函数的handler参数应处理http请求, // 并且初始化handler.servehttp的*request参数的tls和remoteaddr字段(如果未设置)。 // 连接在函数返回时会自动关闭。 tlsnextproto map[string]func(*server, *tls.conn, handler) // connstate字段指定一个可选的回调函数,该函数会在一个与客户端的连接改变状态时被调用。 // 参见connstate类型和相关常数获取细节。 connstate func(net.conn, connstate) // errorlog指定一个可选的日志记录器,用于记录接收连接时的错误和处理器不正常的行为。 // 如果本字段为nil,日志会通过log包的标准日志记录器写入os.stderr。 errorlog *log.logger // 内含隐藏或非导出字段 }
要管理服务端的行为,可以创建一个自定义的server:
s := &http.server{ addr: ":8080", handler: myhander, readtimeout: 10 * time.second, writetimeout: 10 * time.second, maxheaderbytes: 1 << 20, }
到此这篇关于golang中http包的具体使用的文章就介绍到这了,更多相关golang http包内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论