Go语言HTTP服务开发:从标准库到框架
Go语言HTTP服务开发从标准库到框架作为一个写了十几年代码的Go后端老兵我在HTTP服务开发上踩过不少坑。今天就来分享一下Go语言HTTP服务开发的实践经验从标准库到框架。一、标准库net/http1. 基本用法package main import ( fmt net/http ) func helloHandler(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, Hello, World!) } func main() { // 注册路由 http.HandleFunc(/, helloHandler) // 启动服务器 fmt.Println(Server started on :8080) http.ListenAndServe(:8080, nil) }2. 处理不同HTTP方法func handler(w http.ResponseWriter, r *http.Request) { switch r.Method { case http.MethodGet: fmt.Fprintf(w, GET request) case http.MethodPost: fmt.Fprintf(w, POST request) case http.MethodPut: fmt.Fprintf(w, PUT request) case http.MethodDelete: fmt.Fprintf(w, DELETE request) default: http.Error(w, Method not allowed, http.StatusMethodNotAllowed) } }3. 处理URL参数func userHandler(w http.ResponseWriter, r *http.Request) { // 获取URL参数 userID : r.URL.Query().Get(id) if userID { http.Error(w, Missing user ID, http.StatusBadRequest) return } fmt.Fprintf(w, User ID: %s, userID) }4. 读取请求体func postHandler(w http.ResponseWriter, r *http.Request) { // 读取请求体 body, err : io.ReadAll(r.Body) defer r.Body.Close() if err ! nil { http.Error(w, Error reading request body, http.StatusInternalServerError) return } fmt.Fprintf(w, Request body: %s, body) }5. 中间件// 日志中间件 func loggingMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { log.Printf(%s %s, r.Method, r.URL.Path) next.ServeHTTP(w, r) }) } // 认证中间件 func authMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { token : r.Header.Get(Authorization) if token { http.Error(w, Unauthorized, http.StatusUnauthorized) return } // 验证token // ... next.ServeHTTP(w, r) }) } func main() { handler : http.HandlerFunc(helloHandler) // 应用中间件 wrappedHandler : loggingMiddleware(authMiddleware(handler)) http.Handle(/, wrappedHandler) http.ListenAndServe(:8080, nil) }二、使用Gin框架1. 基本用法package main import ( github.com/gin-gonic/gin ) func main() { // 创建Gin引擎 r : gin.Default() // 注册路由 r.GET(/, func(c *gin.Context) { c.JSON(200, gin.H{ message: Hello, World!, }) }) // 启动服务器 r.Run(:8080) }2. 路由组func main() { r : gin.Default() // API路由组 api : r.Group(/api) { // 用户相关路由 users : api.Group(/users) { users.GET(/, listUsers) users.GET(/:id, getUser) users.POST(/, createUser) users.PUT(/:id, updateUser) users.DELETE(/:id, deleteUser) } // 文章相关路由 posts : api.Group(/posts) { posts.GET(/, listPosts) posts.GET(/:id, getPost) posts.POST(/, createPost) } } r.Run(:8080) }3. 中间件// 自定义中间件 func corsMiddleware() gin.HandlerFunc { return func(c *gin.Context) { c.Writer.Header().Set(Access-Control-Allow-Origin, *) c.Writer.Header().Set(Access-Control-Allow-Credentials, true) c.Writer.Header().Set(Access-Control-Allow-Headers, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control, X-Requested-With) c.Writer.Header().Set(Access-Control-Allow-Methods, POST, OPTIONS, GET, PUT, DELETE) if c.Request.Method OPTIONS { c.AbortWithStatus(204) return } c.Next() } } func main() { r : gin.Default() // 应用中间件 r.Use(corsMiddleware()) // 路由 r.GET(/, func(c *gin.Context) { c.JSON(200, gin.H{ message: Hello, World!, }) }) r.Run(:8080) }4. 绑定请求数据// 定义请求结构体 type User struct { Name string json:name binding:required Email string json:email binding:required,email } func createUser(c *gin.Context) { var user User // 绑定JSON数据 if err : c.ShouldBindJSON(user); err ! nil { c.JSON(http.StatusBadRequest, gin.H{error: err.Error()}) return } // 处理数据 // ... c.JSON(http.StatusCreated, user) }5. 错误处理func getUser(c *gin.Context) { id : c.Param(id) user, err : getUserByID(id) if err ! nil { c.JSON(http.StatusNotFound, gin.H{error: User not found}) return } c.JSON(http.StatusOK, user) }三、使用Echo框架1. 基本用法package main import ( github.com/labstack/echo/v4 github.com/labstack/echo/v4/middleware ) func helloHandler(c echo.Context) error { return c.String(200, Hello, World!) } func main() { // 创建Echo实例 e : echo.New() // 应用中间件 e.Use(middleware.Logger()) e.Use(middleware.Recover()) // 注册路由 e.GET(/, helloHandler) // 启动服务器 e.Logger.Fatal(e.Start(:8080)) }2. 路由和参数func userHandler(c echo.Context) error { id : c.Param(id) name : c.QueryParam(name) return c.String(200, fmt.Sprintf(User ID: %s, Name: %s, id, name)) } func main() { e : echo.New() e.Use(middleware.Logger()) e.Use(middleware.Recover()) // 注册路由 e.GET(/users/:id, userHandler) e.Logger.Fatal(e.Start(:8080)) }四、实战案例1. RESTful APIpackage main import ( github.com/gin-gonic/gin net/http ) // 定义数据结构 type User struct { ID string json:id Name string json:name Email string json:email } // 模拟数据库 var users []User{ {ID: 1, Name: 张三, Email: zhangsanexample.com}, {ID: 2, Name: 李四, Email: lisiexample.com}, } // 获取用户列表 func listUsers(c *gin.Context) { c.JSON(http.StatusOK, users) } // 获取单个用户 func getUser(c *gin.Context) { id : c.Param(id) for _, user : range users { if user.ID id { c.JSON(http.StatusOK, user) return } } c.JSON(http.StatusNotFound, gin.H{error: User not found}) } // 创建用户 func createUser(c *gin.Context) { var user User if err : c.ShouldBindJSON(user); err ! nil { c.JSON(http.StatusBadRequest, gin.H{error: err.Error()}) return } users append(users, user) c.JSON(http.StatusCreated, user) } // 更新用户 func updateUser(c *gin.Context) { id : c.Param(id) var updatedUser User if err : c.ShouldBindJSON(updatedUser); err ! nil { c.JSON(http.StatusBadRequest, gin.H{error: err.Error()}) return } for i, user : range users { if user.ID id { users[i] updatedUser c.JSON(http.StatusOK, updatedUser) return } } c.JSON(http.StatusNotFound, gin.H{error: User not found}) } // 删除用户 func deleteUser(c *gin.Context) { id : c.Param(id) for i, user : range users { if user.ID id { users append(users[:i], users[i1:]...) c.JSON(http.StatusOK, gin.H{message: User deleted}) return } } c.JSON(http.StatusNotFound, gin.H{error: User not found}) } func main() { r : gin.Default() // API路由 api : r.Group(/api) { usersGroup : api.Group(/users) { usersGroup.GET(/, listUsers) usersGroup.GET(/:id, getUser) usersGroup.POST(/, createUser) usersGroup.PUT(/:id, updateUser) usersGroup.DELETE(/:id, deleteUser) } } r.Run(:8080) }2. 静态文件服务func main() { r : gin.Default() // 提供静态文件服务 r.Static(/static, ./static) // 提供HTML文件 r.LoadHTMLGlob(templates/*) r.GET(/, func(c *gin.Context) { c.HTML(http.StatusOK, index.html, gin.H{ title: Home Page, }) }) r.Run(:8080) }五、性能优化1. 连接池func main() { // 创建HTTP服务器 server : http.Server{ Addr: :8080, Handler: handler, // 设置连接池参数 ReadTimeout: 15 * time.Second, WriteTimeout: 15 * time.Second, IdleTimeout: 60 * time.Second, MaxHeaderBytes: 1 20, // 1MB } server.ListenAndServe() }2. 缓存// 缓存中间件 func cacheMiddleware(duration time.Duration) gin.HandlerFunc { cache : make(map[string][]byte) timestamps : make(map[string]time.Time) return func(c *gin.Context) { // 生成缓存键 key : c.Request.URL.String() // 检查缓存 if data, ok : cache[key]; ok { if time.Since(timestamps[key]) duration { c.Data(200, application/json, data) c.Abort() return } } // 包装ResponseWriter w : responseWriter{ResponseWriter: c.Writer, body: bytes.Buffer{}} c.Writer w // 处理请求 c.Next() // 缓存响应 if c.Writer.Status() 200 { cache[key] w.body.Bytes() timestamps[key] time.Now() } } } type responseWriter struct { http.ResponseWriter body *bytes.Buffer } func (w *responseWriter) Write(b []byte) (int, error) { w.body.Write(b) return w.ResponseWriter.Write(b) }六、踩坑记录路由冲突不同路由规则可能会冲突需要注意路由顺序中间件顺序中间件的应用顺序很重要会影响请求处理流程请求体读取请求体只能读取一次需要注意保存错误处理要统一错误处理避免在每个处理函数中重复代码性能问题高并发场景下需要注意连接池和缓存的配置七、总结Go语言的HTTP服务开发非常灵活可以使用标准库也可以使用各种框架。作为一个老程序员我的建议是对于简单的服务使用标准库即可对于复杂的应用选择一个适合的框架注重中间件的使用提高代码复用性关注性能优化特别是在高并发场景下统一错误处理提高代码可读性
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2450288.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!