自定义 HTTP 配置

直接使用 http.ListenAndServe() ,像这样:

  1. func main() {
  2. router := gin.Default()
  3. http.ListenAndServe(":8080", router)
  4. }

  1. func main() {
  2. router := gin.Default()
  3. s := &http.Server{
  4. Addr: ":8080",
  5. Handler: router,
  6. ReadTimeout: 10 * time.Second,
  7. WriteTimeout: 10 * time.Second,
  8. MaxHeaderBytes: 1 << 20,
  9. }
  10. s.ListenAndServe()
  11. }

支持 Let’s Encrypt

一个 LetsEncrypt HTTPS 服务器的示例。

  1. package main
  2. import (
  3. "log"
  4. "github.com/gin-gonic/autotls"
  5. "github.com/gin-gonic/gin"
  6. )
  7. func main() {
  8. r := gin.Default()
  9. // Ping 处理器
  10. r.GET("/ping", func(c *gin.Context) {
  11. c.String(200, "pong")
  12. })
  13. log.Fatal(autotls.Run(r, "example1.com", "example2.com"))
  14. }

自定义 autocert 管理器示例。

  1. package main
  2. import (
  3. "log"
  4. "github.com/gin-gonic/autotls"
  5. "github.com/gin-gonic/gin"
  6. "golang.org/x/crypto/acme/autocert"
  7. )
  8. func main() {
  9. r := gin.Default()
  10. // Ping handler
  11. r.GET("/ping", func(c *gin.Context) {
  12. c.String(200, "pong")
  13. })
  14. m := autocert.Manager{
  15. Prompt: autocert.AcceptTOS,
  16. HostPolicy: autocert.HostWhitelist("example1.com", "example2.com"),
  17. Cache: autocert.DirCache("/var/www/.cache"),
  18. }
  19. log.Fatal(autotls.RunWithManager(r, &m))
  20. }

使用 Gin 运行多个服务

查看 问题 并尝试下面示例:

  1. package main
  2. import (
  3. "log"
  4. "net/http"
  5. "time"
  6. "github.com/gin-gonic/gin"
  7. "golang.org/x/sync/errgroup"
  8. )
  9. var (
  10. g errgroup.Group
  11. )
  12. func router01() http.Handler {
  13. e := gin.New()
  14. e.Use(gin.Recovery())
  15. e.GET("/", func(c *gin.Context) {
  16. c.JSON(
  17. http.StatusOK,
  18. gin.H{
  19. "code": http.StatusOK,
  20. "error": "Welcome server 01",
  21. },
  22. )
  23. })
  24. return e
  25. }
  26. func router02() http.Handler {
  27. e := gin.New()
  28. e.Use(gin.Recovery())
  29. e.GET("/", func(c *gin.Context) {
  30. c.JSON(
  31. http.StatusOK,
  32. gin.H{
  33. "code": http.StatusOK,
  34. "error": "Welcome server 02",
  35. },
  36. )
  37. })
  38. return e
  39. }
  40. func main() {
  41. server01 := &http.Server{
  42. Addr: ":8080",
  43. Handler: router01(),
  44. ReadTimeout: 5 * time.Second,
  45. WriteTimeout: 10 * time.Second,
  46. }
  47. server02 := &http.Server{
  48. Addr: ":8081",
  49. Handler: router02(),
  50. ReadTimeout: 5 * time.Second,
  51. WriteTimeout: 10 * time.Second,
  52. }
  53. g.Go(func() error {
  54. return server01.ListenAndServe()
  55. })
  56. g.Go(func() error {
  57. return server02.ListenAndServe()
  58. })
  59. if err := g.Wait(); err != nil {
  60. log.Fatal(err)
  61. }
  62. }

HTTP2 服务器推送

http.Pusher 仅仅被 go1.8+ 支持。 在 golang 官方博客 中查看详细信息。

  1. package main
  2. import (
  3. "html/template"
  4. "log"
  5. "github.com/gin-gonic/gin"
  6. )
  7. var html = template.Must(template.New("https").Parse(`
  8. <html>
  9. <head>
  10. <title>Https Test</title>
  11. <script src="/assets/app.js"></script>
  12. </head>
  13. <body>
  14. <h1 style="color:red;">Welcome, Ginner!</h1>
  15. </body>
  16. </html>
  17. `))
  18. func main() {
  19. r := gin.Default()
  20. r.Static("/assets", "./assets")
  21. r.SetHTMLTemplate(html)
  22. r.GET("/", func(c *gin.Context) {
  23. if pusher := c.Writer.Pusher(); pusher != nil {
  24. // 使用 pusher.Push() 去进行服务器推送
  25. if err := pusher.Push("/assets/app.js", nil); err != nil {
  26. log.Printf("Failed to push: %v", err)
  27. }
  28. }
  29. c.HTML(200, "https", gin.H{
  30. "status": "success",
  31. })
  32. })
  33. // 监听并服务于 https://127.0.0.1:8080
  34. r.RunTLS(":8080", "./testdata/server.pem", "./testdata/server.key")
  35. }

测试

net/http/httptest 包是 HTTP 测试的首选方式。

  1. package main
  2. func setupRouter() *gin.Engine {
  3. r := gin.Default()
  4. r.GET("/ping", func(c *gin.Context) {
  5. c.String(200, "pong")
  6. })
  7. return r
  8. }
  9. func main() {
  10. r := setupRouter()
  11. r.Run(":8080")
  12. }

测试上面代码的示例:

  1. package main
  2. import (
  3. "net/http"
  4. "net/http/httptest"
  5. "testing"
  6. "github.com/stretchr/testify/assert"
  7. )
  8. func TestPingRoute(t *testing.T) {
  9. router := setupRouter()
  10. w := httptest.NewRecorder()
  11. req, _ := http.NewRequest("GET", "/ping", nil)
  12. router.ServeHTTP(w, req)
  13. assert.Equal(t, 200, w.Code)
  14. assert.Equal(t, "pong", w.Body.String())
  15. }

WEBSOKECT

  1. package main
  2. import (
  3. "github.com/gin-gonic/gin"
  4. "github.com/gorilla/websocket"
  5. "net/http"
  6. )
  7. var upGrader = websocket.Upgrader{
  8. CheckOrigin: func (r *http.Request) bool {
  9. return true
  10. },
  11. }
  12. //webSocket请求ping 返回pong
  13. func ping(c *gin.Context) {
  14. //升级get请求为webSocket协议
  15. ws, err := upGrader.Upgrade(c.Writer, c.Request, nil)
  16. if err != nil {
  17. return
  18. }
  19. defer ws.Close()
  20. //读取ws中的数据,一定要,单独write会报错
  21. mt, message, err := ws.ReadMessage()
  22. if err != nil {
  23. return
  24. }
  25. // 一次read多次send
  26. for {
  27. message = []byte("test")
  28. //写入ws数据
  29. err = ws.WriteMessage(mt, message)
  30. if err != nil {
  31. break
  32. }
  33. time.Sleep(time.Second)
  34. }
  35. }
  36. func main() {
  37. bindAddress := "localhost:2303"
  38. r := gin.Default()
  39. r.GET("/ping", ping)
  40. r.Run(bindAddress)
  41. }

错误自定义

  1. package main
  2. import (
  3. "github.com/gin-gonic/gin"
  4. )
  5. func MyRecover(c *gin.Context){
  6. defer func() {
  7. if err:=recover();err!=nil{ //err不等于零值,说明发生了异常
  8. c.AbortWithStatusJSON(200,gin.H{"mes":"500"})
  9. return
  10. }
  11. }()
  12. c.Next()
  13. }
  14. func RouteNotFound(c *gin.Context) {
  15. c.JSON(200,gin.H{"mes":404})
  16. c.Abort()
  17. }
  18. func MethodNotFound(c *gin.Context) {
  19. c.JSON(200,gin.H{"mes":405})
  20. c.Abort()
  21. }
  22. func main() {
  23. r := gin.New()
  24. r.NoRoute(RouteNotFound) //404
  25. r.NoMethod(MethodNotFound)//405
  26. r.GET("/ping", MyRecover,func(c *gin.Context) {
  27. a:= []string{"1","2","3"}
  28. c.String(200,a[3])
  29. })
  30. r.Run() // 在 0.0.0.0:8080 上监听并服务
  31. }

跨域

  1. func Cors() gin.HandlerFunc {
  2. return func(c *gin.Context) {
  3. c.Header("Access-Control-Allow-Origin", c.GetHeader("Origin")) // 允许的请求源
  4. c.Header("Access-Control-Allow-Headers", "Token,SessionId,Content-Type") // 后端可以拿到跨域请求的header
  5. c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS") // 允许的请求方法
  6. c.Header("Access-Control-Allow-Credentials", "true") // 是否允许携带身份凭证
  7. // 能够让客户端的js读取到Header
  8. c.Header("Access-Control-Expose-Headers", "X-Powered-By,xxx")
  9. // 表明在xxx秒内,不需要再发送预检验请求,可以缓存该结果
  10. c.Header("Access-Control-Max-Age", "3600")
  11. //如果method是OPTIONS,直接返回成功
  12. if c.Request.Method == "OPTIONS" {
  13. c.AbortWithStatusJSON(http.StatusOK, "Options Request!")
  14. return
  15. }
  16. // 处理请求
  17. c.Next()
  18. }
  19. }