高级用法

1. 会话 Session

Session 中集成了 http.Client,通过其底层的连接池,在对单个域名发起大量请求时,可以复用连接来极大的提升效率。

session := dw.NewSession()
session.Get("http://httpbin.org/get")

Session 对象拥有 Direwolf API 所有的请求方法。

session := dw.NewSession()
resp, err := session.Post("https://httpbin.org/post", dw.NewPostForm("key", "value"))
resp, err := session.Head("https://httpbin.org/head")
resp, err := session.Put("https://httpbin.org/put", dw.NewPostForm("key", "value"))
resp, err := session.Delete("https://httpbin.org/delete")

以及 Send()

req, err := dw.NewRequest("Get", "https://httpbin.org/get")
if err != nil {
    return
}
resp, err := session.Send(req)

参数优先级

Session 可以跨请求地保持某些参数,例如 headers,超时和代理。但是如果方法的参数和 Session 的参数共存的话,方法的参数会覆盖掉 Session 的参数。

换句话说,方法的参数拥有更高的优先级。例子:

session := dw.NewSession()
sessionHeaders := dw.NewHeaders("User-Agent", "Chrome 88.0")
session.Headers = sessionHeaders  // 设置Session的Headers

normalHeaders := dw.NewHeaders("User-Agent", "Chrome 66.0")
resp, err := session.Get("http://httpbin.org/headers", normalHeaders)
if err != nil {
    return
}
fmt.Println(resp.Text())

输出:

{
  "headers": {
    "Accept-Encoding": "gzip",
    "Host": "httpbin.org",
    "User-Agent": "Chrome 66.0"
  }
}

但是,方法的参数将不会被跨请求的保持,它仅会被使用一次,即使使用的是 Session

2. Session Cookies

Session 可以跨请求地自动管理请求获取的 Cookies:

session := dw.NewSession()
session.Get("http://httpbin.org/cookies/set/name/direwolf")  // 获取cookie
resp, err := session.Get("http://httpbin.org/get")
if err != nil {
    return
}
fmt.Println(resp.Text())

输出:

{
  "args": {},
  "headers": {
    "Accept-Encoding": "gzip",
    "Cookie": "name=direwolf",
    "Host": "httpbin.org",
    "User-Agent": "direwolf - winter is coming"
  },
  "origin": "222.209.233.36, 222.209.233.36",
  "url": "https://httpbin.org/get"
}

添加 Cookies

如果需要手动添加 Cookies 到 Session 中的话,那么可以使用 SetCookies()方法:

session := dw.NewSession()
cookies := dw.NewCookies("key", "value")
session.SetCookies("http://httpbin.org", cookies)
resp, err := session.Get("http://httpbin.org/cookies")
if err != nil {
    return
}
fmt.Println(resp.Text())

输出:

{
  "cookies": {
    "key": "value"
  }
}

获取 Cookies

如果需要获取 Session 中的 Cookies,则可以使用 Cookies() 方法:

session := dw.NewSession()
_, err := session.Get("http://httpbin.org/cookies/set/key/value")
if err != nil {
    return
}
cookies := session.Cookies("http://httpbin.org") // 输入cookies对应的协议和域名
fmt.Println(cookies)

得到的是一个 Cookies 类型的对象。输出:

[key=value]

禁用 CookieJar

如果你想要使用 Session 以得到更高的效率,但又不需要自动管理 Cookie 的话,可以使用 DisableCookieJar() 这个方法禁用掉 CookieJar。

session.DisableCookieJar()

3. Session 设置 Headers,Proxy,Timeout

Session 可以跨请求地保持某些参数,例如 headers,超时和代理。但是如果方法的参数和 Session 的参数共存的话,方法的参数会覆盖掉 Session 的参数。

请求头 Headers

Session 的 Headers 字段类型为 http.Header, 使用 dw.NewHeaders() 方法构造并赋值即可。

session := dw.NewSession()
headers := dw.NewHeaders("User-Agent", "Chrome 76.0")
session.Headers = headers
resp, err := session.Get("http://httpbin.org/headers")
if err != nil {
    return
}
fmt.Println(resp.Text())

输出:

{
  "headers": {
    "Accept-Encoding": "gzip",
    "Host": "httpbin.org",
    "User-Agent": "Chrome 76.0"
  }
}

与其他参数不同,如果方法的 Headers 和 Session 的 Headers 共存,那么它们将会被合并,而如果有同名的 Header,那么方法的 Header 将会覆盖掉同名的 Session 的 Header。

session := dw.NewSession()
sessionHeaders := dw.NewHeaders(
    "User-Agent", "Chrome 88.0",
    "session", "on",
)
session.Headers = sessionHeaders

normalHeaders := dw.NewHeaders(
    "User-Agent", "Chrome 66.0",
    "normal", "on",
)
resp, err := session.Get("http://httpbin.org/headers", normalHeaders)
if err != nil {
    return
}
fmt.Println(resp.Text())

输出:

{
  "headers": {
    "Accept-Encoding": "gzip",
    "Host": "httpbin.org",
    "Normal": "on",
    "Session": "on",
    "User-Agent": "Chrome 66.0"
  }
}

代理 Proxy

Session 的 Proxy 字段类型为 *dw.Proxy 的一个结构体,这个结构体有两个字段 HTTPHTTPS,表示你访问 HTTP 和 HTTPS 网页时可以分别设置不同的代理。

session := dw.NewSession()
proxy := &dw.Proxy{
    HTTP:  "http://127.0.0.1:12333",
    HTTPS: "http://127.0.0.1:12333",
}
session.Proxy = proxy
resp, err := session.Get("http://httpbin.org/ip")
if err != nil {
    return
}
fmt.Println(resp.Text())

输出:

{
  "origin": "88.88.88.88, 88.88.88.88"
}

超时 Timeout

Session 的 Timeout 字段类型为一个简单的整形。

session := dw.NewSession()
session.Timeout = 5

4. Session 高级设置

在 Session 中还有更多可以详细更改的设置,例如每个 Session 可以支持的最大连接数量,或者各类详细的超时时间。

由于 Golang 缺乏对默认值的支持,如果你需要修改这些设置,那么你需要像这样先获取一个默认的 SessionOptions 对象:

option := dw.DefaultSessionOptions()

然后你就可以更改其中的某个或多项设置,并在创建 Session 时将设置传入:

option.DialTimeout = 10
session := dw.NewSession(option)

这是 DefaultSessionOptions 的默认值:

&SessionOptions{
    DialTimeout: 30 * time.Second,		
    DialKeepAlive: 30 * time.Second,		
    MaxConnsPerHost: 0,		
    MaxIdleConns: 100,		
    MaxIdleConnsPerHost: 2,		
    IdleConnTimeout: 90 * time.Second,		
    TLSHandshakeTimeout: 10 * time.Second,		
    ExpectContinueTimeout: 1 * time.Second,		
    DisableCookieJar: false,		
    DisableDialKeepAlives: false,	
}

Timeout 超时

DialTimeout - 建立一个新连接的超时时间。默认值为 30。如果在访问一个域名的过程中需要与多个 IP 地址建立连接,DialTimeout 将会被分成多个部分。

DialKeepAlive - 每次探测活跃连接是否 keep-alives 的时间间隔。如果网络协议或系统不支持 keep-alives,则将会忽略此字段。如果为负值,将会禁用 keep-alives 探测。

IdleConnTimeout - 连接池中持久连接保持在空闲状态的时间,如果超过这个时间,持久连接将会被关闭。值为 0 表示不限制超时。

TLSHandshakeTimeout - TLS 握手的超时时间。值为 0 表示不限制超时。

ExpectContinueTimeout - 如果请求的 header 中有 Expect: 100-continue,从完全发送请求的 header 开始,直到服务端返回响应的第一条 header 的超时时间。如果值为 0,表示发送请求后,不等待服务端的响应,立即发送响应体。

Connections 连接数量

MaxConnsPerHost - 与每个域名建立的最大连接数,包括正在拨号、活跃的、空闲的连接。如果超过此连接数量,那么拨号将会堵塞。值为 0 表示不限制。

MaxIdleConns - 控制 Session 持久连接的最大总数量。值为 0 表示不限制。

如果需要发起大量请求,推荐提高此项设置的值。

MaxIdleConnsPerHost - 控制 Session 与每个域名的持久连接的最大数量。值为 0 将会使用默认值 2

如果需要对单一域名发起大量请求,推荐提高此项设置的值。

其他

DisableCookieJar - Session 默认会启用 CookieJar 来管理 Cookie,如果你不希望启用 CookieJar,可以将此项设置改为 true 来禁用 CookieJar。

DisableDialKeepAlives - 默认情况下,HTTP1.1 会启用持久连接。如果你希望禁用持久连接,强制使用短连接,可以将此项设置改为 true 来禁用持久连接。