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 服务不可或缺的特性。
评论前必须登录!
注册