云计算百科
云计算领域专业知识百科平台

演示 HTTP 服务器的基础实现与优雅管理

Go HTTP服务器实现

实现了一个简单的HTTP服务器,它能够处理客户端请求并返回 JSON响应

1.主要功能

  • 创建一个监听在本地127.0.0.1:8282的地址 HTTP 服务器

    srv := &http.Server{
    Addr:         "127.0.0.1:8282", // 监听地址
    Handler:      nil,              // 使用默认的多路复用器
    }

  • 设置了请求读取超时、响应写入超时和空闲连接超时

    srv := &http.Server{
    ReadTimeout: 10 * time.Second, // 请求读取超时
    WriteTimeout: 10 * time.Second, // 响应写入超时
    IdleTimeout: 120 * time.Second, // 空闲连接超时
    }

  • 注册了一个又处理函数 Myhandler,处理 /go路径的请求

    http.HandleFunc("/go", Myhandler)

2.请求处理函数

  • 打印客户端连接信息、请求方法、URL路劲和请求体内容

    fmt.Println(r.RemoteAddr, "连接成功")

    fmt.Println("method:", r.Method) // 请求方式:GET POST DELETE PUT UPDATE

    fmt.Println("url:", r.URL.Path)   // URL 路径

  • 读取请求体数据并进行错误处理

    body, err := io.ReadAll(r.Body) // 读取请求体并正确处理错误
    if err != nil {
    http.Error(w, "读取请求体失败…", http.StatusBadRequest)
    }

  • 设置响应头 JSON 格式,并且返回状态码 200

    // 设置响应头为JSON格式,并返回状态码200
    w.Header().Set("Content-Type", "application/json") // 设置 JSON 响应

    w.WriteHeader(http.StatusOK) // 200

  • 返回 JSON 响应 {"Message":"www.baidu.com"}

    w.Write([]byte(`{"Message":"www.baidu.com"}`)) // 可自行写入自己想要的内容

3.自动请求测试

  • 服务器启动后,立即向自己发送一个 GET 请求到 /go 路径

    res, err := http.Get("http://127.0.0.1:8282/go")

  • 接收并打印响应状态、响应头和响应体内容

fmt.Println(r.RemoteAddr, "连接成功")

fmt.Println("method:", r.Method) // 请求方式:GET POST DELETE PUT UPDATE

fmt.Println("url:", r.URL.Path) // URL 路径

4.优雅关闭机制

  • 监听系统信号 (SIGINT 和 SIGTERM),用于除法服务器关闭

  • 收到关闭信号后,使用 5 秒的超时上下文执行优雅关闭

  • 确保现有请求处理完成后关闭服务器

quit := make(chan os.Signal, 1) // 创建通道

signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)

<-quit

fmt.Println("正在关闭服务器…")

ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()

if err := srv.Shutdown(ctx); err != nil {
log.Fatalf("服务器关闭失败:%v", err)
}

5.整体代码

package main

import (
"context"
"fmt"
"io"
"log"
"net/http"
"os"
"os/signal"
"syscall"
"time"
)

func Myhandler(w http.ResponseWriter, r *http.Request) {
fmt.Println(r.RemoteAddr, "连接成功")

fmt.Println("method:", r.Method) // 请求方式:GET POST DELETE PUT UPDATE

fmt.Println("url:", r.URL.Path) // URL 路径

body, err := io.ReadAll(r.Body) // 读取请求体并正确处理错误
if err != nil {
http.Error(w, "读取请求体失败…", http.StatusBadRequest)
}

defer r.Body.Close() // 优雅关闭
fmt.Println("body: ", string(body))

// 设置 JSON 响应头
w.Header().Set("Content-Type", "application/json") // 设置 JSON 响应

w.WriteHeader(http.StatusOK)

// 设置返回有效的 JSON 格式
w.Write([]byte(`{"Message":"www.baidu.com"}`)) // 写入内容
}

func main() {
// 注册路由
http.HandleFunc("/go", Myhandler)

srv := &http.Server{
Addr: "127.0.0.1:8282", // 监听地址
Handler: nil, // 使用默认的多路复用器
ReadTimeout: 10 * time.Second,
WriteTimeout: 10 * time.Second,
IdleTimeout: 120 * time.Second,
}
go srv.ListenAndServe()

// 启动服务器(后台运行)
go func() {
fmt.Println("服务器在启动 http://127.0.0.1:8282/")
if err := srv.ListenAndServe(); err != nil {
log.Fatal("ListenAndServe: ", err)
}
}()

// 等待服务器(简单延迟)
time.Sleep(1 * time.Second)

// 发送自动请求
res, err := http.Get("http://127.0.0.1:8282/go") // 获取 http 地址
if err != nil {
fmt.Println("请求失败:", err)
return
}
defer res.Body.Close() // 防止资源泄露

// 200OK
fmt.Println("响应状况:", res.Status) // 200OK

fmt.Println("响应头部:", res.Header)

// 响应体读取
body, err := io.ReadAll(res.Body)

if err != nil {
fmt.Println("读取响应失败…", err)
return
}

fmt.Println("读取完毕…")
fmt.Println(string(body))

// 优雅关闭服务器
quit := make(chan os.Signal, 1) // 创建通道

signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)

<-quit // 发送通道

fmt.Println("正在关闭服务器…")

ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)

defer cancel()

if err := srv.Shutdown(ctx); err != nil {
log.Fatalf("服务器关闭失败:%v", err)
}
fmt.Println("服务器已关闭")
}

6.技术亮点

  • 优雅关闭机制

    // 优雅关闭服务器
    quit := make(chan os.Signal, 1) // 创建通道

    signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)

    <-quit // 发送通道

    fmt.Println("正在关闭服务器…")

    ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)

    defer cancel()

    if err := srv.Shutdown(ctx); err != nil {
    log.Fatalf("服务器关闭失败:%v", err)
    }
    fmt.Println("服务器已关闭")

    说明:

    • 使用 Go 的信号处理机制捕获系统终端信号 (SIGTERM)

    • 通过 context.WithTimeout 创建一个带超时的上下文,确保服务器指定时间关闭

    • srv.Shudown() 方法实现了优雅关闭,允许完成当前请求而不接受新请求

    • 这是生成环境中非常重要的特性,可避免服务中断导致的数据丢失

  • 请求超时机制

    srv := &http.Server{
    ReadTimeout: 10 * time.Second,
    WriteTimeout: 10 * time.Second,
    IdleTimeout: 120 * time.Second,
    }

    说明:

    • 设置了三种超时机制,防止慢客户端攻击和资源耗尽

    • ReadTimeout :限制读取请求头和请求体的时间

    • WriteTimeout:限制写入响应的时间

    • IdleTimeout : 限制空闲连接的存活时间

    • 这些设置增强了服务器的安全性和稳定性

  • HTTP 服务器自测试机制

    // 启动服务器(后台运行)
    go func() {
    fmt.Println("服务器在启动 http://127.0.0.1:8282/")
    if err := srv.ListenAndServe(); err != nil {
    log.Fatal("ListenAndServe: ", err)
    }
    }()

    // 等待服务器(简单延迟)
    time.Sleep(1 * time.Second)

    // 发送自动请求
    res, err := http.Get("http://127.0.0.1:8282/go") // 获取 http 地址

    说明:

    • 服务器启动后立即进行测试,验证服务可用性

    • 这是一种简单 ”冒烟测试“,确保服务能够正常响应请求

    • 开发和部署过程中非常有用,可以快速检测配置错误

  • 清晰的请求处理流程

    func Myhandler(w http.ResponseWriter, r *http.Request) {
    fmt.Println(r.RemoteAddr, "连接成功")

    fmt.Println("method:", r.Method) // 请求方式:GET POST DELETE PUT UPDATE

    fmt.Println("url:", r.URL.Path) // URL 路径

    body, err := io.ReadAll(r.Body) // 读取请求体并正确处理错误
    if err != nil {
    http.Error(w, "读取请求体失败…", http.StatusBadRequest)
    }

    defer r.Body.Close() // 优雅关闭
    fmt.Println("body: ", string(body))

    // 设置 JSON 响应头
    w.Header().Set("Content-Type", "application/json") // 设置 JSON 响应

    w.WriteHeader(http.StatusOK)

    // 设置返回有效的 JSON 格式
    w.Write([]byte(`{"Message":"www.baidu.com"}`)) // 写入内容
    }

    说明:

    • 遵循了清晰的请求处理模式:接收请求 —> 处理数据 —> 返回响应

    • 正确处理了请求体的读取和关闭,防止资源泄露

    • 设置了适当的响应头和状态码,符合 HTTP 协议规范

  • 使用 Go 的并发模型

    go srv.ListenAndServe()

    说明:

    • 利用 Go 的 goroutine 轻量级线程特性,在后台启动 HTTP 服务器

    • 这允许主程序继续执行其他任务 (自测试),而不必阻塞等待

    • 体现了 Go 语言在并发编程方面简洁和高效性

  • 总结

    小项目的技术两点主要体现在服务器的可靠性、安全性和可测试性方面。特别是优雅关闭机制,请求超时控制,是构建生产级别 HTTP 服务不可或缺的特性。

    赞(0)
    未经允许不得转载:网硕互联帮助中心 » 演示 HTTP 服务器的基础实现与优雅管理
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!