net/http 是Go 语言标准库中的一个重要包,用于处理 HTTP 请求和响应,支持客户端和服务器功能。它提供了简洁高效的接口来处理常见的 HTTP 协议操作,包括请求的发送、响应的接收、HTTP 服务器的搭建等。对于 Web 开发、API 接口调用、以及构建 HTTP 服务,net/http 是非常常用的工具。

1、net/http 包概述

net/http 包提供了丰富的功能,包括:

·HTTP 客户端:发送HTTP 请求,处理响应。

·HTTP 服务器:处理客户端的HTTP 请求,生成并返回响应。

·路由和处理器:通过多种方式处理不同类型的HTTP 请求。

·中间件支持:通过处理器链实现请求预处理和后处理。

2、 安装和导入

Go 语言的net/http 包是标准库的一部分,无需安装,只需直接导入即可使用:

import "net/http"

3、 作为 HTTP 客户端使用

net/http 包提供了发送HTTP 请求的功能,可以通过http.Get()、http.Post() 等方法发送请求。以下是客户端的一些常见用法。

3.1 发送 GET 请求

最常用的HTTP 请求方法之一是GET,它用于从服务器获取资源。

package main

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

func main() {
    // 发送 GET 请求
    resp, err := http.Get("https://jsonplaceholder.typicode.com/posts")
    
    if err !=nil {
        fmt.Println("Error:", err)
        return
    }

    defer resp.Body.Close()
    
    // 读取响应内容
    body, err := ioutil.ReadAll(resp.Body)
    
    if err !=nil {
        fmt.Println("Error reading body:", err)
    return
    }
    
    // 输出响应内容
    fmt.Println("Response Body:",string(body))
}

解释:

·http.Get(url):发送GET 请求并返回*http.Response 对象。

·defer resp.Body.Close():在函数退出时关闭响应体,避免资源泄漏。

·ioutil.ReadAll():读取响应体并返回字节切片。

3.2 发送 POST 请求

POST 请求通常用于向服务器提交数据。

package main

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

func main() {
    // 准备发送的数据
    data := []byte(`{"title": "foo", "body": "bar", "userId": 1}`)
    
    // 发送 POST 请求
    resp, err := http.Post("https://jsonplaceholder.typicode.com/posts","application/json", bytes.NewBuffer(data))
    if err !=nil {
        fmt.Println("Error:", err)
        return
    }
    
    defer resp.Body.Close()

    // 读取响应内容
    body, err := ioutil.ReadAll(resp.Body)
    
    if err !=nil {
        fmt.Println("Error reading body:", err)
        return
    }
    
    // 输出响应内容
    fmt.Println("Response Body:",string(body))
}

解释:

·http.Post(url, contentType, body):发送POST 请求,contentType 是请求体的内容类型(如JSON),body 是请求体。

·bytes.NewBuffer(data):将数据包装为io.Reader,传递给http.Post()。

3.3 发送带有自定义头部的请求

你可以使用http.NewRequest() 创建自定义的HTTP 请求,并设置请求头。

package main

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

func main() {
    // 创建自定义请求
    req, err := http.NewRequest("GET","https://jsonplaceholder.typicode.com/posts",nil)
    if err !=nil {
        log.Fatal(err)
    }
    
    // 设置请求头
    req.Header.Set("Authorization","Bearer my-token")
    
    // 发送请求
    client := &http.Client{}
    resp, err := client.Do(req)
    if err !=nil {
        log.Fatal(err)
    }
    
    defer resp.Body.Close()
    // 读取响应内容
    body, err := ioutil.ReadAll(resp.Body)
    if err !=nil {
        log.Fatal(err)
    }
    
    // 输出响应内容
    fmt.Println("Response Body:",string(body))
}

解释:

·http.NewRequest(method, url, body):创建一个新的HTTP 请求,可以设置请求方法、URL 和请求体。

·client.Do(req):使用自定义http.Client 发送请求。

·req.Header.Set():设置请求头。

4、 作为 HTTP 服务器使用

net/http 还可以用于构建HTTP 服务器,处理来自客户端的请求并生成响应。

4.1 创建简单的 HTTP 服务器

使用http.HandleFunc() 方法,你可以为不同的URL 路径指定处理函数。

package main

import (
    "fmt"
    "net/http"
)

func handler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w,"Hello, %s!", r.URL.Path[1:])
}

func main() {
    // 注册路由和处理函数
    http.HandleFunc("/", handler)

    // 启动 HTTP 服务器
    fmt.Println("Starting server on :8080...")
    
    if err := http.ListenAndServe(":8080",nil); err !=nil {
        fmt.Println("Error starting server:", err)
    }
}

解释:

·http.HandleFunc("/", handler):注册一个处理函数handler,它将处理所有来自/ 路径的请求。

·http.ListenAndServe(":8080", nil):启动一个HTTP 服务器,监听8080 端口,处理请求。

4.2 路由和多处理函数

你可以注册多个路由和对应的处理函数来处理不同的URL 路径。

package main

import (
    "fmt"
    "net/http"
)

func helloHandler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w,"Hello World!")
}

func aboutHandler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w,"About Us!")
}

func main() {
    // 注册多个路由和处理函数
    http.HandleFunc("/hello", helloHandler)
    http.HandleFunc("/about", aboutHandler)

    // 启动 HTTP 服务器
    fmt.Println("Starting server on :8080...")
    if err := http.ListenAndServe(":8080",nil); err !=nil {
        fmt.Println("Error starting server:", err)
    }
}

解释:

·通过http.HandleFunc("/path", handler) 注册多个路由,处理不同的请求路径。

5、 使用 HTTP 中间件

中间件是HTTP 处理过程中的一环,可以用来执行请求预处理、日志记录、身份验证等操作。Go 语言的net/http 包本身不直接提供中间件支持,但你可以通过包装现有的处理函数实现中间件。

5.1 创建简单的日志中间件

package main

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

// 日志中间件
func logRequest(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        start := time.Now()
        next.ServeHTTP(w, r)
        fmt.Printf("Request: %s %s, Duration: %v\n", r.Method, r.URL.Path, time.Since(start))
    })
}

func helloHandler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w,"Hello World!")
}

func main() {
    // 注册路由和处理函数
    http.HandleFunc("/hello", helloHandler)

    // 使用日志中间件
    http.Handle("/hello", logRequest(http.HandlerFunc(helloHandler)))

    // 启动 HTTP 服务器
    fmt.Println("Starting server on :8080...")
    if err := http.ListenAndServe(":8080",nil); err !=nil {
        fmt.Println("Error starting server:", err)
    }
}

解释:

·logRequest 是一个中间件,它包裹了请求处理函数,记录请求的开始时间和结束时间。

·http.Handle("/hello", logRequest(http.HandlerFunc(helloHandler))):将中间件应用到处理/hello 路径的请求。

6、 应用场景

·构建RESTful API:net/http 可以用来创建Web 服务端,处理 GET、POST、PUT、DELETE 等 HTTP 请求。

·Web 应用开发:你可以使用net/http 来开发简单的Web 应用,响应用户请求并返回动态页面。

·爬虫和数据抓取:net/http 适用于编写爬虫程序,通过发送HTTP 请求获取网页数据。

·客户端API 请求:通过net/http 可以方便地向其他服务器发送HTTP 请求,获取数据或与其他服务交互。

更多推荐