Golang——http包

        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,
	}

 

  • 6
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值