GO_网络编程---HTTP 编程

发布时间:2026/7/28 14:01:56
GO_网络编程---HTTP 编程 一、HTTP 基础前置知识1. 网页访问完整流程用户输入域名域名发送至DNS 服务器DNS 解析返回对应服务器 IP 地址客户端通过拿到的 IP 地址向 Web 服务器发起 TCP 连接客户端发送HTTP 请求包给服务端Web 服务器处理请求返回HTTP 响应包网页 HTML / 资源客户端浏览器渲染页面展示给用户。2. 基础概念SSL/TLSHTTP 明文传输不安全SSL/TLS 为 HTTP 加密层加密后协议为 HTTPS域名 URL域名方便人类记忆用于 DNS 解析成 IPURL完整资源定位地址包含域名、路径、请求参数HTTP 核心通信模型客户端浏览器 / 程序→ 请求包 → 服务端 → 响应包 → 客户端一问一答短连接。报文结构请求报文请求行 请求头key:value键值对 空行 请求体响应报文状态行 响应头 空行 响应体常见状态码200 OK请求成功404 Not Found请求资源不存在。二、底层 TCP 通信HTTP 底层基于 TCPHTTP 本质是封装后的 TCP 应用层协议先掌握原生 TCP 服务端 / 客户端。1. TCP 服务端代码go运行package main import ( fmt net ) func main() { // 1. 监听端口8000 listener, err : net.Listen(tcp, :8000) if err ! nil { fmt.Println(Listen err , err) return } defer listener.Close() // 延迟关闭监听套接字 // 2. 阻塞等待客户端连接 conn, errl : listener.Accept() if errl ! nil { fmt.Println(Accept errl , errl) return } defer conn.Close() // 延迟关闭客户端连接 // 3. 读取客户端发送的数据 buf : make([]byte, 1024*4) // 4KB缓冲区 n, err2 : conn.Read(buf) if n 0 { fmt.Println(Read err , err2) return } fmt.Printf(#%v#, string(buf[:n])) }2. TCP 客户端手动构造 HTTP 请求报文原生 TCP 手动拼接标准 HTTP1.1 请求报文向 HTTP 服务端发送请求并接收响应go运行package main import ( fmt net ) func main() { // 1. 主动连接TCP服务端 conn, err : net.Dial(tcp, :8000) if err ! nil { fmt.Println(dial err , err) return } defer conn.Close() // 2. 手动构造标准HTTP GET请求报文 requestBuf : GET /go HTTP/1.1\r\nAccept: image/gif, image/jpeg, image/pjpeg, application/x-ms-application, application/xamlxml, application/x-ms-xbap, */*\r\nAccept-Language: zh-Hans-CN,zh-Hans;q0.8,en-US;q0.5,en;q0.3\r\nUser-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 10.0; WOW64; Trident/7.0; .NET4.0C; .NET4.0E; .NET CLR 2.0.50727; .NET CLR 3.0.30729; .NET CLR 3.5.30729)\r\nAccept-Encoding: gzip, deflate\r\nHost: 127.0.0.1:8000\r\nConnection: Keep-Alive\r\n\r\n // 发送请求包服务端才会返回响应 conn.Write([]byte(requestBuf)) // 3. 读取服务器返回的HTTP响应报文 buf : make([]byte, 1024*4) n, errl : conn.Read(buf) if n 0 { fmt.Println(Read err , errl) return } // 打印完整响应报文 fmt.Printf(#%v#, string(buf[:n])) }三、Go 标准库 net/http 编程重点Go 内置net/http封装了 TCP 底层逻辑无需手动处理套接字快速实现 HTTP 服务端、客户端。核心 API 说明http.HandleFunc(path string, handler func(ResponseWriter, *Request))注册路由与处理函数http.ListenAndServe(addr string, handler Handler) error监听端口启动 HTTP 服务addr监听地址如:8000、127.0.0.1:8000handler统一处理器填 nil 使用默认多路分发器。1. 最简 HTTP 服务端固定路由访问地址http://127.0.0.1:8000/gogo运行package main import ( fmt net/http ) // 业务逻辑处理函数 func myHandler(w http.ResponseWriter, r *http.Request) { // w向客户端写响应数据 // r读取客户端请求信息 fmt.Fprintln(w, hello world) } func main() { // 注册路由访问/go 自动执行myHandler http.HandleFunc(/go, myHandler) // 监听8000端口启动HTTP服务 http.ListenAndServe(127.0.0.1:8000, nil) }2. 全局路由 HTTP 服务端根路径 /所有路径都匹配该处理函数使用w.Write()返回字节数据go运行package main import ( net/http ) // w给客户端回复数据 // req读取客户端发送的数据 func HandConn(w http.ResponseWriter, req *http.Request) { w.Write([]byte(hello go)) // 写入响应体 } func main() { // 注册根路由所有访问路径都会进入该函数 http.HandleFunc(/, HandConn) // 监听绑定8000端口 http.ListenAndServe(:8000, nil) }3. HTTP 服务端获取客户端完整请求信息通过*http.Request结构体提取请求方法、URL、请求头、请求体go运行package main import ( fmt net/http ) func HandConn(w http.ResponseWriter, r *http.Request) { // 打印客户端请求信息 fmt.Println(r.Method , r.Method) // 请求方法 GET/POST fmt.Println(r.URL , r.URL) // 请求URL与参数 fmt.Println(r.Header , r.Header) // 请求头所有key-value fmt.Println(r.Body , r.Body) // 请求体流 // 返回响应给客户端 w.Write([]byte(hello go)) } func main() { http.HandleFunc(/, HandConn) http.ListenAndServe(:8000, nil) }4. HTTP 客户端http.Get 网页请求模拟浏览器发起 GET 请求读取服务端响应状态、响应头、网页源码go运行package main import ( fmt net/http ) func main() { // 发起GET请求 resp, err : http.Get(http://www.baidu.com) if err ! nil { fmt.Println(http.Get err , err) return } defer resp.Body.Close() // 必须关闭响应体释放资源 // 打印响应基础信息 fmt.Println(Status , resp.Status) // 状态文本 200 OK fmt.Println(StatusCode , resp.StatusCode) // 状态码 200/404 fmt.Println(Header , resp.Header) // 服务端响应头 fmt.Println(Body , resp.Body) // 网页数据流 // 循环读取完整网页内容 buf : make([]byte, 4*1024) var tmp string for { n, err : resp.Body.Read(buf) if n 0 { fmt.Println(read err , err) break } tmp string(buf[:n]) } fmt.Println(网页完整内容\n, tmp) }四、实战网络爬虫基于 http 包爬虫四大步骤明确目标确定爬取网站、分页规则爬取HTTP GET 获取页面完整源码提取筛选需要的有效数据持久化数据写入文件 / 数据库。1. 单任务爬虫串行爬取速度慢go运行package main import ( fmt net/http os strconv ) // HttpGet 请求url返回页面完整源码 func HttpGet(url string) (result string, err error) { resp, err1 : http.Get(url) if err1 ! nil { err err1 return } defer resp.Body.Close() // 循环读取网页body buf : make([]byte, 1024*4) for { n, err : resp.Body.Read(buf) if n 0 { // 读取完毕或异常 fmt.Println(resp.Body.Read err , err) break } result string(buf[:n]) } return } // 爬取指定区间页面 func DoWork(start, end int) { fmt.Printf(正在爬取 %d 到 %d 的页面\n, start, end) // 贴吧分页规则pn(页码-1)*50 for i : start; i end; i { url : http://tieba.baidu.com/f?kw%E7%BB%9D%E5%9C%B0%E6%B1%82%E7%94%9Fieutf-8pn strconv.Itoa((i-1)*50) fmt.Println(当前爬取url , url) // 爬取页面源码 result, err : HttpGet(url) if err ! nil { fmt.Println(HttpGet err , err) continue } // 写入html文件保存 fileName : strconv.Itoa(i) .html f, err1 : os.Create(fileName) if err1 ! nil { fmt.Println(os.Create err1 , err1) continue } f.WriteString(result) f.Close() } } func main() { var start, end int fmt.Printf(请输入起始页 ( 1) :) fmt.Scan(start) fmt.Printf(请输入终止页 ( 起始页) :) fmt.Scan(end) DoWork(start, end) }2. 并发版爬虫goroutine 通道速度大幅提升核心优化每页启动独立 goroutine 并发爬取channel 做同步等待所有任务完成go运行package main import ( fmt net/http os strconv ) // 公共函数请求网页获取源码 func HttpGet(url string) (result string, err error) { resp, err1 : http.Get(url) if err1 ! nil { err err1 return } defer resp.Body.Close() buf : make([]byte, 1024*4) for { n, err : resp.Body.Read(buf) if n 0 { fmt.Println(resp.Body.Read err , err) break } result string(buf[:n]) } return } // 单个页面爬取协程函数 func SpiderPage(i int, pageChan chan- int) { url : http://tieba.baidu.com/f?kw%E7%BB%9D%E5%9C%B0%E6%B1%82%E7%94%9Fieutf-8pn strconv.Itoa((i-1)*50) fmt.Printf(正在爬第%d页网页%s\n, i, url) // 爬取页面 result, err : HttpGet(url) if err ! nil { fmt.Println(HttpGet err , err) pageChan - i return } // 保存文件 fileName : strconv.Itoa(i) .html f, err1 : os.Create(fileName) if err1 ! nil { fmt.Println(os.Create err1 , err1) pageChan - i return } f.WriteString(result) f.Close() // 爬取完成向通道发送页码标记任务结束 pageChan - i } func main() { var start, end int fmt.Printf(请输入起始页 ( 1) :) fmt.Scan(start) fmt.Printf(请输入终止页 ( 起始页) :) fmt.Scan(end) // 创建同步通道缓冲大小为总页面数 pageChan : make(chan int, end-start1) // 循环启动goroutine并发爬取 for i : start; i end; i { go SpiderPage(i, pageChan) } // 阻塞等待所有页面爬取完成 for i : start; i end; i { -pageChan } close(pageChan) fmt.Println(全部页面爬取完成) }五、学习总结HTTP 是应用层协议底层依赖 TCPDNS 负责域名转 IP 建立连接Go 原生net包可手动实现 TCP 通信手动拼接 HTTP 报文理解底层原理net/http标准库封装 TCP 细节一行代码快速搭建 HTTP 服务端 / 客户端服务端HandleFunc注册路由ListenAndServe启动服务客户端http.Get快速发起网页请求注意defer resp.Body.Close()释放资源爬虫基于 HTTP 客户端实现串行爬取效率低搭配 goroutinechannel 实现并发爬虫提速。