- 前言
- Go 与操作系统
- Go 内部机制
- Go 基本数据类型
- 4 组合类型的使用
- 5 数据结构
- 6 Go package 中不为人知的知识
- 7 反射和接口
- 8 Go UNIX 系统编程
- 08.1 关于 UNIX 进程
- 08.2 flag 包
- 8.2 flag 包
- 08.3 io.Reader 和 io.Writer 接口
- 08.4 bufio 包
- 08.5 读取文本文件
- 08.6 从文件中读取所需的数据量
- 08.7 为什么我们使用二进制格式
- 08.8 读取 CSV 文件
- 08.9 写入文件
- 08.10 从磁盘加载和保存数据
- 08.11 再看strings包
- 08.12 关于bytes包
- 08.13 文件权限
- 08.14 处理 Unix 信号
- 08.15 Unix 管道编程
- 08.16 遍历目录树
- 08.17 使用 ePBF
- 08.18 关于 syscall.PtraceRegs
- 08.19 跟踪系统调用
- 08.20 User ID 和 group ID
- 08.21 其他资源
- 08.22 练习
- 08.23 总结
- 9 并发 Goroutines、Channel 和 Pipeline
- 10 Go 并发-进阶讨论
- 11 代码测试、优化及分析
- 12 Go 网络编程基础
- 13 网络编程 - 构建服务器与客户端
12.8 追踪 HTTP
Go 支持用 net/http/httptraces
标准包追踪 HTTP!这个包允许您追踪一个 HTTP 请求的解析。net/http/httptraces
标准包的使用将在 httpTrace.go
中加以说明,它分为五部分进行讲解。
httpTrace.go
的第一部分如下:
package main
import (
"fmt"
"io"
"net/http"
"net/http/httptrace"
"os"
)
如您所料,您需要引入 net/http/httptrace
包来追踪 HTTP。
httpTrace.go
的第二部分代码如下:
func main() {
if len(os.Args) != 2 {
fmt.Println("Usage: URL\n")
return
}
URL := os.Args[1]
client := http.Client{}
在这部分,我们读取命令行参数并创建一个新的 http.Client
变量。由于这是您第一次在执行中看到 http.Client
对象,所以关于它我们就多讲一些。http.Client
对象发送请求到服务器并获得一个响应。它的 Transport
字段允许您设置各种 HTTP 细节来替代默认值。
注意,您不应该在发布的软件中使用 http.Client
对象的默认值,因为这些值没有指定请求超时,它会影响程序的性能以及 goroutines的运行。而且,根据设计 http.Client
对象能够安全的用于并发程序。
httpTrace.go
的第三段代码如下:
req, _ := http.NewRequest("GET", URL, nil)
trace := &httptrace.ClientTrace{
GotFirstResponseByte: func() {
fmt.Println("First response byte!")
},
GotConn: func(connInfo httptrace.GotConnInfo) {
fmt.Printf("Got Conn: %+v\n", connInfo)
},
DNSDone: func(dnsInfo httptrace.DNSDoneInfo) {
fmt.Printf("DNS Info: %+v\n", dnsInfo)
},
ConnectStart: func(network, addr string) {
fmt.Println("Dial start")
},
ConnectDone: func(network, addr string, err error) {
fmt.Println("Dial done")
},
WroteHeaders: func() {
fmt.Println("Wrote headers")
},
}
上面这段就是全部追踪 HTTP 请求的代码了。httptrace.ClientTrace
对象定义了使我们感兴趣的事件。当一个事件发生时,相关代码就会被执行。您能够在 net/http/httptrace
包的文档中找到更多信息,关于支持的事件和它们的目的。
httpTrace.go
的第四部分如下:
req = req.WithContext(httptrace.WithClientTrace(req.Context(), trace))
fmt.Println("Requesting data from server!")
_, err := http.DefaultTransport.RoundTrip(req)
if err != nil {
fmt.Println(err)
return
}
httptrace.WithClientTrace()
函数基于给定的父上下文返回一个新的上下文;而 http.DefaultTransport.RoundTrip()
方法包裹 http.DefaultTransport.RoundTrip()
目的是告诉它要追踪当前的请求。注意,Go HTTP 跟踪被设计为追踪单个 http.Transport.RoundTrip
的事件。然而,当服务一个单独的HTTP 请求时,由于您可能有多个 URL 重定向,所以您需要能够识别出当前的请求。
httpTrace.go
的剩余代码如下:
response, err := client.Do(req)
if err != nil {
fmt.Println(err)
return
}
io.Copy(os.Stdout, response.Body)
}
最后这部分是使用 Do()
执行实际的请求到 web 服务器,获取 HTTP 数据,并把它显示在屏幕上。
执行 httpTrace.go
将产生如下非常翔实的输出:
$ go run httpTrace.go http://localhost:8001/
Requesting data from server!
DNS Info: {Addrs: [{IP:::1 Zone:} {IP:127.0.0.1 Zone:}] Err:<nil> Coalesced:false}
Dial start
Dial done
Got Conn: {Conn:0xc42014200 Reused:false WasIdel:false IdleTime:0s}
Wrote headers
First response byte!
DNS Info: {Addrs: [{IP:::1 Zone:} {IP:127.0.0.1 Zone:}] Err:<nil> Coalesced:false}
Dial start
Dial done
Got Conn: {Conn:0xc420142008 Reused:false WasIdle:false IdleTime:0s}
Wrote headers
First response byte!
Serving: /
考虑到 httpTrace.go
打印从 HTTP 服务器返回的全部 HTML 数据,当您用一个真实的 web 服务测试时,您可能会得到太多输出,所以在这我们就使用 www.go
这个 web 服务器了。
如果您有时间看
net/http/httptrace
包的源码,在 http://golang.org/src/net/http/httptrace/trace.go,您会立马意识到net/http/httptrace
是个相当低级的包,它使用context
,reflect
和internal/nettrace
包实现它的功能。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论