48、Go语言基础 - 网络编程 - HTTP Web 编程

作者: 温新

分类: 【Go基础】

阅读: 306

时间: 2023-12-05 00:41:39

hi,我是温新

Web 工作流程

Web 工作流程的简单归纳:

1、客户机通过 TCP/IP 协议建立到服务器的 TCP 连接;

2、客户端向服务器发送 HTTP 协议请求包,请求服务器中的资源;

3、服务器端向客户端发送 HTTP 协议应答包,若请求的资源包含动态语言的内容,则服务器会调用动态语言的解释引擎处理动态内容,并把处理好的内容返回给发起资源请求的客户端;

4、客户端与服务器端断开。

HTTP 协议

HTTP (HyperText Transfer Protocol,超文本传输协议)是互联网上应用最为广泛的一种网络协议,定义了客户端和服务器端之间请求与响应的传输标准。

Go语言内置的net/http包十分的优秀,提供了HTTP客户端和服务端的实现。

HTTP 服务端

处理 HTTP 请求

http.ListenAndServe 是 Go 语言标准库中的一个函数,用于启动一个 HTTP 服务器,监听指定的网络地址和端口,然后处理来自客户端的 HTTP 请求。

ListenAndServe

方法格式如下:

func ListenAndServe(addr string, handler http.Handler) error

参数解释:

  • addr:一个字符串,表示服务器要监听的网络地址和端口。它通常是一个字符串,格式为host:port,其中host可以是 IP 地址或主机名,port是端口号。例如,:8080表示在本地的 8080 端口上监听,"0.0.0.0:80" 表示在所有网络接口上监听 80 端口。
  • handler:一个实现了 http.Handler 接口的对象,通常是一个处理 HTTP 请求的处理器。处理器是一个函数或对象,用于处理不同路径的请求,可以根据请求路径来调用相应的处理函数。
  • 返回值:函数会返回一个 error,用于指示是否启动服务器时发生错误。如果一切正常,返回 nil

HandleFunc

http.HandleFunc 是 Go 语言标准库中用于设置 HTTP 请求处理函数的函数。它的主要作用是将指定的处理函数与特定的 URL 路径关联起来,以便在接收到匹配路径的 HTTP 请求时执行该处理函数。

方法格式如下:

func HandleFunc(pattern string, handler func(http.ResponseWriter, *http.Request))

参数解释:

  • pattern:一个字符串,用于指定要匹配的URL路径模式。可以包括动态部分,例如/user/{id},其中{id}表示一个参数,后续可以通过处理函数访问它。
  • handler:一个处理函数,它是一个带有两个参数的函数,第一个参数是 http.ResponseWriter,用于编写HTTP响应,第二个参数是 *http.Request,包含HTTP请求的信息。

HTTP Go Web 简单案例

package main

import (
    "fmt"
    "net/http"
)

func main() {
    // 使用 http.HandleFunc 来关联 "/goweb" 路径的 HTTP 请求处理函数
    http.HandleFunc("/goweb", func(w http.ResponseWriter, request *http.Request) {
        // 在接收到匹配的 HTTP 请求时,执行这个匿名函数

        // 使用 fmt.Fprintln 写入 "Go Web" 到 HTTP 响应,发送给客户端
        fmt.Fprintln(w, "Go Web")
    })

    // 启动 HTTP 服务器,监听端口 8888
    err := http.ListenAndServe(":8888", nil)
    if err != nil {
        fmt.Println("HTTP server failed to start: ", err)
    }
}

这个示例创建了一个简单的HTTP服务器,当访问http://localhost:8888/goweb时,它会响应"Go Web"。同时,这演示了使用http.HandleFunc来创建基本的路由和请求处理。

处理 HTTPS 请求

http.ListenAndServeTLS 是 Go 语言标准库中用于启动支持TLS/SSL的HTTPS服务器的函数。它允许你使用加密传输层安全性(TLS)来保护传输的数据。

ListenAndServeTLS

方法格式如下:

func ListenAndServeTLS(addr, certFile, keyFile string, handler http.Handler) error

参数解释:

  • addr:一个字符串,表示服务器要监听的网络地址和端口。格式为host:port,例如 :443 表示默认HTTPS端口。
  • certFile:一个字符串,指定服务器的TLS/SSL证书文件的路径。该证书文件包含公钥和服务器身份信息。
  • keyFile:一个字符串,指定服务器的TLS/SSL私钥文件的路径。该私钥文件用于解密TLS连接。
  • handler:一个实现了 http.Handler 接口的对象,通常是一个处理HTTP请求的处理器。
  • 返回值:函数返回一个 error,用于指示是否启动服务器时发生错误。如果一切正常,返回 nil

ListenAndServeTLSListenAndServe 和行为是一致的,区别在于只处理 HTTPS 请求。

package main

import (
    "fmt"
    "net/http"
)

func main() {
    // 使用 http.HandleFunc 来设置处理 "/go" 路径的 HTTP 请求处理函数
    http.HandleFunc("/go", func(w http.ResponseWriter, r *http.Request) {
        // 在接收到匹配的 HTTP 请求时,执行这个匿名函数

        // 使用 fmt.Fprintln 将 "Hello, HTTPS World!" 写入 http.ResponseWriter,这将作为 HTTP 响应发送给客户端
        fmt.Fprintln(w, "Hello, HTTPS World!")
    })

    // 启动 HTTPS 服务器,监听默认 HTTPS 端口(443)
    // 需要提供 TLS/SSL 证书文件 "server.crt" 和私钥文件 "server.key" 来启用加密连接
    err := http.ListenAndServeTLS(":443", "server.crt", "server.key", nil)
    if err != nil {
        fmt.Println("HTTPS server failed to start: ", err)
    }
}

这个示例创建了一个简单的 HTTPS 服务器,当访问 https://localhost/go 时,它会响应 "Hello, HTTPS World!"。需要提供有效的证书和私钥文件,或者使用自签名证书进行测试。

HTTP 客户端

Go 内置的 net/http 包提供了最简洁的 HTTP 客户端实现,不需要借助第三方网络通信库就可以直接使用 HTTP 中用得最多的 GET 和 POST 方式请求数据。

基本的 HTTP/HTTPS 请求

net/http 包的 Client 类型提供了如下几个方法,利用最简洁的方式实现 HTTP 请求:

func (c *Client) Get(url string) (r *Response, err error)
func (c *Client) Post(url string, bodyType string, body io.Reader) (r *Response, err error)
func (c *Client) PostForm(url string, data url.Values) (r *Response, err error)
func (c *Client) Head(url string) (r *Response, err error)
func (c *Client) Do(req *Reqeust) (resp *Response, error)

程序使用完成后 response 必须关闭。

resp, err := http.Get("http://example.com/")
if err != nil {
	// handle error
}
// 关闭响应主体
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)

GET 请求案例

要请求一个资源,只需调用 http.Get() 方法即可。其格式如下:

func Get(url string) (resp *Response, err error)

参数解释:

  • url:一个字符串,表示要发送 GET 请求的目标 URL。
  • 返回值:Get 函数返回一个指向 http.Response 结构的指针,以及一个 error。如果请求成功,errornil,并且 resp 包含了从服务器接收到的响应数据。如果请求失败,error 将包含错误信息。

以下是一个简单的示例代码,使用 http.Get 发起 GET 请求并处理响应:

package main

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

func main() {
	// 要发送 GET 请求的 URL
	url := "https://www.ziruchu.com"

	// 使用 http.Get 发起 GET 请求
	resp, err := http.Get(url)
	if err != nil {
		fmt.Println("Get reqeuset failed ", err)
		return
	}

	// 确保在函数结束时关闭响应体
	defer resp.Body.Close()

	// 读取响应体的内容
	body, err := io.ReadAll(resp.Body)
	if err != nil {
		fmt.Println("Failed to read response body: ", err)
		return
	}

	// 打印响应状态码和响应内容
	fmt.Println("Response Status Code:", resp.Status)
	fmt.Println("Response Body:", string(body))
}

在这个示例中,http.Get 被用来发送 GET 请求到 https://www.ziruchu.com,并获取响应。随后,我们读取响应体的内容,并打印响应的状态码和内容。

GET 携带参数的请求案例

package main

import (
	"fmt"
	"net/http"
)

func main() {
	// 处理 HTTP 请求
	http.HandleFunc("/user", func(w http.ResponseWriter, r *http.Request) {
		// 解析 URL 参数
		r.ParseForm()
		queryParams := r.URL.Query()
		response := "请求参数:\n"
		// 遍历所有参数并构造响应
		for key, values := range queryParams {
			for _, value := range values {
				response += fmt.Sprintf("%s:%s\n", key, value)
			}
		}

		// 将响应写回到浏览器
		fmt.Fprintln(w, response)
	})

	// 启动 HTTP 服务器,监听端口 9999
	err := http.ListenAndServe(":9999", nil)
	if err != nil {
		fmt.Println("HTTP server failed to start:", err)
	}
}

在此示例中,设置了一个 HTTP 请求处理函数,当浏览器发起 GET 请求到/user路径时,它将解析 URL 参数并遍历所有参数内容。然后,它将所有参数的内容构造成响应,并将响应发送回浏览器。

可以在浏览器中访问 http://localhost:9999/user?nam=lucy&age=19&sex=1,将会看到响应包含所有参数的内容

Post 请求案例

http.Post 是 Go 标准库 net/http 中用于发送 HTTP POST 请求的函数。其格式如下:

func Post(url, contentType string, body io.Reader) (resp *Response, err error)

参数解释:

  • url:一个字符串,表示要发送 POST 请求的目标 URL。
  • contentType:一个字符串,表示请求体的数据格式,通常是 MIME 类型,如 "application/json""application/x-www-form-urlencoded"
  • body:一个 io.Reader 接口,通常是 bytes.Readerstrings.Reader,包含了要发送的数据。这可以是请求体的内容,如 JSON 数据或表单数据。
  • 返回值:Post 函数返回一个指向 http.Response 结构的指针,以及一个 error。如果请求成功,errornil,并且 resp 包含了从服务器接收到的响应数据。如果请求失败,error 将包含错误信息。

以下是一个简单的案例:

package main

import (
	"bytes"
	"fmt"
	"net/http"
)

func main() {
	// 模拟外部传入的 JSON 数据
	jsonData := []byte(`{"name": "王美丽", "age": 19}`)

	// 目标 URL
	url := "http://192.168.31.90/api"

	// 设置请求头中的 Content-Type
	contentType := "application/json"

	// 使用 http.Post 发起 POST 请求
	resp, err := http.Post(url, contentType, bytes.NewBuffer(jsonData))
	if err != nil {
		fmt.Println("POST request failed: ", err)
		return
	}
	defer resp.Body.Close()

	// 处理响应
	if resp.StatusCode == http.StatusOK {
		fmt.Println("POST request was successful!")
		// 在这里可以进一步处理服务器的响应数据
	} else {
		fmt.Println("POST request failed with status code: ", resp.Status)
	}
}

在这个示例中,使用 http.Post 发送了一个 JSON 数据,其中 jsonData 包含了参数,url 是目标 URL,contentType 设置为 JSON 数据的 MIME 类型。请替换 urljsonData 为实际的值和数据,以适应你的需求。

PostForm 案例

http.PostForm 是 Go 标准库 net/http 中的一个函数,用于发送 HTTP POST 请求,并以表单形式传递参数。其格式如下:

func PostForm(url string, data url.Values) (resp *Response, err error)

参数解释:

  • url:一个字符串,表示要发送 POST 请求的目标 URL。
  • data:一个 url.Values 类型的参数,通常用于表示表单数据,其中键和值以键值对的形式存储。
  • 返回值:PostForm 函数返回一个指向 http.Response 结构的指针,以及一个 error。如果请求成功,errornil,并且 resp 包含了从服务器接收到的响应数据。如果请求失败,error 将包含错误信息。

以下是简单的案例:

package main

import (
    "fmt"
    "net/http"
    "net/url"
)

func main() {
    // 要发送 POST 请求的 URL
    url := "https://example.com/user"

    // 准备表单参数
    formData := url.Values{}
    formData.Set("name", "王美丽")
    formData.Set("age", "19")

    // 使用 http.PostForm 发起 POST 请求
    resp, err := http.PostForm(url, formData)
    if err != nil {
        fmt.Println("POST request failed: ", err)
        return
    }
    defer resp.Body.Close() // 确保在函数结束时关闭响应体

    // 在这里处理响应...
}
请登录后再评论