Go Book / 1 Go Basics / 19 Go网络编程(二): H T T P服务及 H T T P客户端

19 Go网络编程(二): H T T P服务及 H T T P客户端

一、HTTP概述

HTTP协议是Hyper Text Transfer Protocol(超文本传输协议)的缩写,是用于从万维网(WWW:World Wide Web )服务器传输超文本到本地浏览器的传送协议。HTTP是一个基于TCP/IP通信协议来传递数据(HTML 文件, 图片文件, 查询结果等)。

HTTP是基于客户端/服务端(C/S)的架构模型,通过一个可靠的链接来交换信息,是一个无状态的请求/响应协议。一个HTTP"客户端"是一个应用程序(Web浏览器或其他任何客户端),通过连接到服务器达到向服务器发送一个或多个HTTP的请求的目的。一个HTTP"服务器"同样也是一个应用程序(通常是一个Web服务,如Apache Web服务器或IIS服务器等),通过接收客户端的请求并向客户端发送HTTP响应数据。HTTP使用统一资源标识符(Uniform Resource Identifiers, URI)来传输数据和建立连接。

HTTP 请求报文结构

HTTP请求报文结构.png

HTTP 响应报文信息

HTTP响应报文信息.jpg

二、Go 搭建HTTP服务器

1.基于HTTP的Web服务

大多数编程语言都支持web服务器的开发,市面上也有许多针对web服务的解决方案,如PHP的LANMP方案,JAVA的Tomcat等,其开发web服务系统通常都需要搭建一堆核心构建和周边设施。Go对基于http的web开发非常友好,仅适用其标准的net/http包你就可以构建自己的web服务,且其并发能力似乎天生就为web而准备。

这里有非常全面的net/http中文翻译,该包是go开发web服务的核心包,应深入了解以下。

2.编写一个简单的HTTP服务端

步骤:

  • 编写针对特定需求的处理器并为其设置访问路径;
  • http.ListenAndServe("{ip}:{port}", nil)就可启动一个监听服务;
package main

import (
	"fmt"
	"io/ioutil"
	"net/http"
)

//搭建基本的http服务器 http_server.go
func main() {
	//设置http服务处理函数1
	http.HandleFunc("/jianshu", func(writer http.ResponseWriter, request *http.Request) {
        //这里使用一个http客户端方法获取jianshu首页数据
		response, err := http.Get("http://www.jianshu.com")
		SErrorFunc(err, "http.Get")
		bytes, err := ioutil.ReadAll(response.Body)
		SErrorFunc(err, "ioutil.ReadAll")
		writer.Write(bytes)
	})

	//设置http服务处理函数2
	http.HandleFunc("/hi", func(writer http.ResponseWriter, request *http.Request) {
		writer.Write([]byte("Hi Gopher!!!"))
	})

	//设置http服务处理函数3:直接绑定函数
	http.HandleFunc("/showrequest", ShowRequest)

	//服务绑定端口并启动服务
	http.ListenAndServe("0.0.0.0:8888", nil)
	fmt.Println("服务端已启动....监听端口:8888")
}

func ShowRequest(writer http.ResponseWriter, request *http.Request) {

	req, err := ioutil.ReadAll(request.Body)
	SErrorFunc(err, "ioutil.ReadAll")

	writer.Write([]byte("请求Method:" + request.Method))
	writer.Write([]byte("请求Host:" + request.Host))
	writer.Write([]byte("请求客户端地址:" + request.RemoteAddr))
	writer.Write([]byte("请求链接:" + request.RequestURI))
	writer.Write([]byte("请求主机:" + request.Host))
	writer.Write([]byte("请求头:" + request.Header.Get("")))
	writer.Write(req)

}

//生成可执行文件
go build http_server.go

//运行可执行文件即可启动http监听服务

如示例中设置了三个web处理器,在浏览器键入:

  • http://localhost:8888/jianshu
  • http://localhost:8888/hi
  • http://localhost:8888/showrequest

就可看到本地web服务

三、HTTP 客户端

Go的net/http网络包提供了HTTP客户端的封装方法,直接使用http的标准方法向网络发起请求,许多爬虫程序都是基于http客户端实现,这里做一个常用的GET和POST方法演示

编写一个HTTP客户端:
//基本的httpclient请求
/*
·发起百度搜索的GET请求:"http://www.baidu.com/s?wd=简书",打印回复的内容
·对https://httpbin.org/post发起post请求,携带表单数据,键值自拟,打印回复的内容
·表单数据类型 application/x-www-form-urlencoded,表单读取API:strings.NewReader("rmb=0.5&hobby=接客和约汉"))
*/

func BaseHttpClient() {

	//1. http.Get请求
	resp1, err := http.Get("http://www.baidu.com/s?wd=简书")
	MErrorHandler(err, "http.Get")
	defer resp1.Body.Close()

	bytes1, err := ioutil.ReadAll(resp1.Body)
	MErrorHandler(err, "ioutil.ReadAll")

	fmt.Printf("这是响应头:%s\n", resp1.Header)
	fmt.Printf("这是响应体:%s\n", string(bytes1))

	//2. http.Post请求
	resp2, err := http.Post("https://httpbin.org/post", "application/x-www-form-urlencoded", strings.NewReader("name=fun&age=18&desc=developer"))
	CErrorFunc(err, "http.Post")
	defer resp2.Body.Close()

	bytes2, err := ioutil.ReadAll(resp2.Body)
	CErrorFunc(err, "ioutil.ReadAll")
	fmt.Printf("Post请求响应体:%s\n", string(bytes2))

}

func MErrorHandler(err error, where string) {
	if err != nil {
		fmt.Println("此处有错:", err)
		os.Exit(1)
	}
}