golang中如何使用 net/http 库

发布时间:2021-07-20 15:12:59 作者:Leah
来源:亿速云 阅读:201
# Golang中如何使用 net/http 库

## 引言

Go语言(Golang)以其简洁的语法、高效的并发模型和强大的标准库而闻名。在标准库中,`net/http`包是构建HTTP客户端和服务器的核心工具。本文将深入探讨如何使用`net/http`库,涵盖从基础到进阶的各个方面。

## 1. net/http库概述

`net/http`是Go标准库中用于处理HTTP协议的包,它提供了:

- HTTP客户端实现
- HTTP服务端实现
- URL解析
- Cookie管理
- 文件上传处理
- 连接复用等高级特性

### 1.1 主要组件

```go
// 客户端相关
type Client struct{...}
func (c *Client) Do(req *Request) (*Response, error)

// 服务端相关
type Server struct{...}
func ListenAndServe(addr string, handler Handler) error

2. 创建HTTP服务端

2.1 基本HTTP服务

package main

import (
    "fmt"
    "net/http"
)

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

func main() {
    http.HandleFunc("/hello", helloHandler)
    fmt.Println("Server starting on port 8080...")
    http.ListenAndServe(":8080", nil)
}

2.2 使用自定义路由

func main() {
    mux := http.NewServeMux()
    mux.HandleFunc("/hello", helloHandler)
    mux.HandleFunc("/about", aboutHandler)
    
    server := &http.Server{
        Addr:    ":8080",
        Handler: mux,
    }
    
    log.Fatal(server.ListenAndServe())
}

2.3 中间件模式

func loggingMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        log.Printf("Request: %s %s", r.Method, r.URL.Path)
        next.ServeHTTP(w, r)
    })
}

func main() {
    mux := http.NewServeMux()
    mux.HandleFunc("/", homeHandler)
    
    wrappedMux := loggingMiddleware(mux)
    
    http.ListenAndServe(":8080", wrappedMux)
}

3. 处理HTTP请求

3.1 读取请求数据

func userHandler(w http.ResponseWriter, r *http.Request) {
    // 获取查询参数
    name := r.URL.Query().Get("name")
    
    // 读取POST表单数据
    err := r.ParseForm()
    if err != nil {
        http.Error(w, "Bad Request", http.StatusBadRequest)
        return
    }
    email := r.Form.Get("email")
    
    // 读取JSON请求体
    var user User
    if err := json.NewDecoder(r.Body).Decode(&user); err != nil {
        http.Error(w, err.Error(), http.StatusBadRequest)
        return
    }
}

3.2 处理不同HTTP方法

func apiHandler(w http.ResponseWriter, r *http.Request) {
    switch r.Method {
    case http.MethodGet:
        // 处理GET请求
    case http.MethodPost:
        // 处理POST请求
    case http.MethodPut:
        // 处理PUT请求
    default:
        http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
    }
}

4. 构建HTTP响应

4.1 基本响应

func jsonHandler(w http.ResponseWriter, r *http.Request) {
    data := map[string]interface{}{
        "status":  "success",
        "message": "Hello, JSON!",
    }
    
    w.Header().Set("Content-Type", "application/json")
    w.WriteHeader(http.StatusOK)
    json.NewEncoder(w).Encode(data)
}

4.2 文件服务

func fileHandler(w http.ResponseWriter, r *http.Request) {
    http.ServeFile(w, r, "./static/image.png")
}

// 或者使用FileServer
func main() {
    fs := http.FileServer(http.Dir("./static"))
    http.Handle("/static/", http.StripPrefix("/static/", fs))
}

5. 创建HTTP客户端

5.1 基本GET请求

func fetchData() {
    resp, err := http.Get("https://api.example.com/data")
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()
    
    body, err := io.ReadAll(resp.Body)
    if err != nil {
        log.Fatal(err)
    }
    
    fmt.Println(string(body))
}

5.2 高级客户端配置

func customClient() {
    client := &http.Client{
        Timeout: 10 * time.Second,
        Transport: &http.Transport{
            MaxIdleConns:        10,
            IdleConnTimeout:    30 * time.Second,
            DisableCompression: true,
        },
    }
    
    req, err := http.NewRequest("GET", "https://api.example.com", nil)
    if err != nil {
        log.Fatal(err)
    }
    
    req.Header.Add("Authorization", "Bearer token123")
    
    resp, err := client.Do(req)
    // 处理响应...
}

6. 处理HTTPS

6.1 服务端HTTPS

func main() {
    mux := http.NewServeMux()
    mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        w.Write([]byte("Secure connection!"))
    })
    
    err := http.ListenAndServeTLS(
        ":443",
        "server.crt",
        "server.key",
        mux,
    )
    if err != nil {
        log.Fatal(err)
    }
}

6.2 客户端跳过证书验证

func insecureClient() {
    tr := &http.Transport{
        TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
    }
    client := &http.Client{Transport: tr}
    
    resp, err := client.Get("https://self-signed.example.com")
    // 处理响应...
}

7. 高级特性

7.1 连接池管理

func pooledClient() {
    client := &http.Client{
        Transport: &http.Transport{
            MaxIdleConns:        100,
            MaxIdleConnsPerHost: 10,
            IdleConnTimeout:    90 * time.Second,
        },
        Timeout: 10 * time.Second,
    }
    
    // 复用client进行多次请求
}

7.2 处理超时

func timeoutExample() {
    // 服务端设置超时
    server := &http.Server{
        Addr:         ":8080",
        ReadTimeout:  5 * time.Second,
        WriteTimeout: 10 * time.Second,
    }
    
    // 客户端设置超时
    client := &http.Client{Timeout: 5 * time.Second}
}

7.3 优雅关闭服务

func gracefulShutdown() {
    server := &http.Server{Addr: ":8080"}
    
    go func() {
        if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
            log.Fatalf("listen: %s\n", err)
        }
    }()
    
    quit := make(chan os.Signal, 1)
    signal.Notify(quit, os.Interrupt)
    <-quit
    
    ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
    defer cancel()
    
    if err := server.Shutdown(ctx); err != nil {
        log.Fatal("Server forced to shutdown:", err)
    }
}

8. 性能优化技巧

  1. 复用Client实例:避免为每个请求创建新Client
  2. 启用连接复用:合理配置Transport参数
  3. 使用BufferPool:减少内存分配
  4. 启用压缩:对于大响应启用gzip压缩
  5. 合理设置超时:避免资源耗尽
var client = &http.Client{
    Transport: &http.Transport{
        MaxIdleConns:        100,
        MaxIdleConnsPerHost: 10,
        IdleConnTimeout:    30 * time.Second,
    },
    Timeout: 10 * time.Second,
}

9. 常见问题与解决方案

9.1 内存泄漏

问题:未关闭响应体

resp, err := http.Get(url)
// 错误:缺少 defer resp.Body.Close()

解决方案

defer resp.Body.Close()

9.2 连接耗尽

问题:未限制并发连接数

解决方案

transport := &http.Transport{
    MaxIdleConns:        100,
    MaxConnsPerHost:    10,
}

9.3 请求超时

解决方案

client := &http.Client{
    Timeout: 5 * time.Second,
}

10. 实际应用示例

10.1 REST API服务

type User struct {
    ID    int    `json:"id"`
    Name  string `json:"name"`
    Email string `json:"email"`
}

func usersHandler(w http.ResponseWriter, r *http.Request) {
    switch r.Method {
    case http.MethodGet:
        // 获取用户列表
        users := []User{...}
        json.NewEncoder(w).Encode(users)
    case http.MethodPost:
        // 创建新用户
        var user User
        json.NewDecoder(r.Body).Decode(&user)
        // 保存用户...
        w.WriteHeader(http.StatusCreated)
    }
}

10.2 文件上传

func uploadHandler(w http.ResponseWriter, r *http.Request) {
    // 限制上传大小
    r.ParseMultipartForm(10 << 20) // 10MB
    
    file, handler, err := r.FormFile("file")
    if err != nil {
        http.Error(w, err.Error(), http.StatusBadRequest)
        return
    }
    defer file.Close()
    
    // 保存文件
    dst, err := os.Create(handler.Filename)
    // ...处理错误
    defer dst.Close()
    
    io.Copy(dst, file)
    fmt.Fprintf(w, "Upload successful")
}

结论

Go的net/http包提供了强大而灵活的工具来构建HTTP客户端和服务端应用。通过本文的介绍,您应该已经掌握了:

  1. 创建HTTP服务的基本方法
  2. 处理各种HTTP请求和响应的技巧
  3. 构建高效HTTP客户端的最佳实践
  4. 高级配置和性能优化方法

无论是构建简单的Web服务还是复杂的分布式系统,net/http都能提供坚实的基础。随着Go语言的不断发展,这个标准库也在持续改进,值得开发者深入学习和掌握。

延伸阅读

  1. Go官方net/http文档
  2. Go Web编程
  3. 高级Go网络编程

希望本文能帮助您更好地理解和使用Go语言的net/http库! “`

推荐阅读:
  1. golang导出csv乱码解决方法
  2. Golang 基于chrome浏览器语音识别web演示系统WebHTK开发之 UI篇

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

golang

上一篇:golang 中 context的作用是什么

下一篇:怎么修改gazebo物理参数

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》