一, HTTP协议客户端实现
1, 使用http.NewRequest()方法
首先创建一个client(客户端)对象,其次创建一个request(请求)对象,最后使用client发生request。详情如下:
package main
import (
"fmt"
"net/http"
)
func main() {
testHttpNewRequest()
}
func testHttpNewRequest() {
// 创建一个客户端
client := http.Client{}
// 创建一个请求,请求方式既可以是GET,也可以是POST
request, err := http.NewRequest("GET", "http://www.baidu.com/", nil)
CheckErr(err)
// 客户端发送请求
cookName := &http.Cookie{Name: "username", Value: "JACK"}
// 添加cookie
request.AddCookie(cookName)
response, err := client.Do(request)
CheckErr(err)
// 设置请求头
request.Header.Set("Accept-Language", "zh-cn")
defer response.Body.Close()
// 查看请求头数据
fmt.Printf("Header:%+v
", request.Header)
fmt.Printf("响应状态码:%v
", response.StatusCode)
// 操作数据
if response.StatusCode == 200 {
//data, err := ioutil.ReadAll(response.Body)
fmt.Println("网络请求成功")
CheckErr(err)
//fmt.Println(string(data))
} else {
fmt.Println("网络请求失败", response.Status)
}
}
// 检查错误
func CheckErr(err error) {
defer func() {
if ins, ok := recover().(error); ok {
fmt.Println("程序出现异常: ", ins.Error())
}
}()
if err != nil {
panic(err)
}
}
2, 使用client.Get()方法
这种方法一共两个步骤,先创建一个client(客户端)对象,然后使用client调用Get()方法
package main
import (
"fmt"
"net/http"
)
func main() {
testClientGet()
}
func testClientGet() {
// 创建客户端
client := http.Client{}
// 通过client去请求
response, err := client.Get("http://www.baidu.com")
CheckErr(err)
fmt.Printf("响应状态码:%v
", response.StatusCode)
if response.StatusCode == 200 {
fmt.Println("网络请求成功")
defer response.Body.Close()
}
}
// 检查错误
func CheckErr(err error) {
defer func() {
if ins, ok := recover().(error); ok {
fmt.Println("程序出现异常: ", ins.Error())
}
}()
if err != nil {
panic(err)
}
}
3, 使用client.Post()或client.PostForm()方法
这种方法也是两个步骤,先创建一个client(客户端)对象,然后使用client调用POST或PostForm()方法。其实client的Post()或PostForm()方法,就是对http.NewRequest()封装。
4, 使用http.Get()方法
这个方法只有一个步骤,http的Get()方法就是对DefaultClient.Get()封装。
package main
import (
"fmt"
"net/http"
)
func main() {
testHttpGet()
}
func testHttpGet() {
// 获取服务器的数据
response, err := http.Get("http://www.baidu.com")
CheckErr(err)
fmt.Printf("响应状态码:%v
", response.StatusCode)
if response.StatusCode == 200 {
defer response.Body.Close()
fmt.Println("网络请求成功")
CheckErr(err)
} else {
fmt.Println("请求失败", response.Status)
}
}
// 检查错误
func CheckErr(err error) {
defer func() {
if ins, ok := recover().(error); ok {
fmt.Println("程序出现异常: ", ins.Error())
}
}()
if err != nil {
panic(err)
}
}
5, 使用http.Post()或http.PostForm()方法
http的Post()函数或PostForm就是对DefaultClient.Post()或DefaultClient.PostForm()的封装。这个方法也只有一个 步骤
package main
import (
"fmt"
"net/http"
"net/url"
"strings"
)
func main() {
testHttpPost()
}
func testHttpPost() {
// 构造参数
data := url.Values{"City": {"上海"}}
// 参数转化成body
reader := strings.NewReader(data.Encode())
// 发起Post请求MIME格式
response, err := http.Post("http://wwww.weibo.com.cn/", "application/x-www-form-urlencoded", reader)
CheckErr(err)
fmt.Printf("响应状态码:%v
", response.StatusCode)
if response.StatusCode == 200 {
// 操作响应数据
defer response.Body.Close()
fmt.Println("请求成功")
CheckErr(err)
} else {
fmt.Println("请求失败", response.Status)
}
}
// 检查错误
func CheckErr(err error) {
defer func() {
if ins, ok := recover().(error); ok {
fmt.Println("程序出现异常: ", ins.Error())
}
}()
if err != nil {
panic(err)
}
}
二, HTTP协议服务端实现
① 启动Web服务的几种方式
1, 使用http.FileServer()方法
http.FileServer()搭建的服务器只提供静态文件的访问。应为这种web服务只支持静态文件访问,所以称之为静态文件访问。
http.ListenAndServer()函数用来启动Web服务,绑定并监听http端口。其中第一个参数为监听地址,第二个参数表示提供文件访问服务的HTTP处理器Hander。
Handler是一个接口,其中只有ServeHTTP(http.ResponseWrite, *http.Request)这一个方法,只有实现了该方法,就自动实现Handler接口,具体声明如下所示
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}
http.FileServer()正好可以返回Handler类型,也就是可以提供文件访问服务的HTTP处理器。
FileServer()的参数是FileSystem接口,可以使用http.Dir()来指定服务端文件所在的路径。如果该路径中存在index.html文件,则会有限显示html文件,否则会显示文件目录。
package main
import "net/http"
func main() {
testFileServer()
}
func testFileServer(){
http.ListenAndServe(":2003", http.FileServer(http.Dir("/Users/jack_zhou/Documents")))
}
2, 使用http.HandleFunc()方法
http.HandleFunc()的作用是注册网络访问的路由。因为它采用的是默认路由分发人物方式,所以称为默认的多路由分发服务。
HandleFunc()的第一个参数是请求路径的匹配模式,第二个参数是一个函数类型,表示这个请求需要处理的事情。
作为服务器,随时会处理很多的请求,如果没有路由,就需要使用if else 或switch这样的分支语言进行判断,实在太辛苦。Go提供一个ServeMux()方法去分发任务。HandleFunc()其实就是直接将参数交给DefaultServeMux()来进行处理。
func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
DefaultServeMux.HandleFunc(pattern, handler)
}
HandleFunc()是一个典型的函数式编程例子,而函数式编也是GO的特色
HandleFunc()的第二个参数其实就是Handler接口中的ServeHTTP()方法。所以这第二个参数其实就是实现了Handler接口的handler实例。
通过http.HandleFunc()注册网络路由时,http.ListenAndServer()的第二个参数为nil,这意味着服务端采用默认的http.DefauleServeMux进行分发处理。
package main
import (
"fmt"
"net/http"
)
func main() {
// 绑定路径,触发对应方法
http.HandleFunc("index", indexHandler)
// 绑定端口
// 第一个桉树为监听地址,第二个参数为服务端处理程序,通常为nil,这意味着服务端调用http.DefaultServeMux进行处理。
err := http.ListenAndServe("localhost:3013", nil)
fmt.Println(err)
}
func indexHandler(w http.ResponseWriter, r *http.Request) {
fmt.Println("/index...")
w.Write([]byte("首页"))
}
② 服务端获取客户请求的数据
1,Get方式传递参数
- r.ParseForm(),返回error,判断是否解析传参时出错
- r.Form属性,返回url.Values,他是map[string][]string类型。一般情况下,使用r.FormValue(key)方法更简洁简便
- r.FormValue(key)方法可以根据客户端传参的key获取对应的值。
- 其中r表示*http.Request类型,w表示http.ResponseWriter类型。
2,Post方式传递参数
Post传参分为两种情况
- 普通表单请求(直接使用r.PostFormValue(key)方法,可以根据表单的name取到对应的传值。)
- 文件上传请求(使用r.FormFile(key)方法,根据文件上传控件的name取到上传文件爱你的File和FileHeader对象,然后通过io的copy()操作实现文件上传。)
3,获取cookies中的值
Cookie是一个结构体,可以通过http.SetCookie()函数设置Cookie,通过r.Cookie()方法获取cookie