自定义 HTTP 配置
直接使用 http.ListenAndServe()
,像这样:
func main() {
router := gin.Default()
http.ListenAndServe(":8080", router)
}
或
func main() {
router := gin.Default()
s := &http.Server{
Addr: ":8080",
Handler: router,
ReadTimeout: 10 * time.Second,
WriteTimeout: 10 * time.Second,
MaxHeaderBytes: 1 << 20,
}
s.ListenAndServe()
}
支持 Let’s Encrypt
一个 LetsEncrypt HTTPS 服务器的示例。
package main
import (
"log"
"github.com/gin-gonic/autotls"
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
// Ping 处理器
r.GET("/ping", func(c *gin.Context) {
c.String(200, "pong")
})
log.Fatal(autotls.Run(r, "example1.com", "example2.com"))
}
自定义 autocert 管理器示例。
package main
import (
"log"
"github.com/gin-gonic/autotls"
"github.com/gin-gonic/gin"
"golang.org/x/crypto/acme/autocert"
)
func main() {
r := gin.Default()
// Ping handler
r.GET("/ping", func(c *gin.Context) {
c.String(200, "pong")
})
m := autocert.Manager{
Prompt: autocert.AcceptTOS,
HostPolicy: autocert.HostWhitelist("example1.com", "example2.com"),
Cache: autocert.DirCache("/var/www/.cache"),
}
log.Fatal(autotls.RunWithManager(r, &m))
}
使用 Gin 运行多个服务
查看 问题 并尝试下面示例:
package main
import (
"log"
"net/http"
"time"
"github.com/gin-gonic/gin"
"golang.org/x/sync/errgroup"
)
var (
g errgroup.Group
)
func router01() http.Handler {
e := gin.New()
e.Use(gin.Recovery())
e.GET("/", func(c *gin.Context) {
c.JSON(
http.StatusOK,
gin.H{
"code": http.StatusOK,
"error": "Welcome server 01",
},
)
})
return e
}
func router02() http.Handler {
e := gin.New()
e.Use(gin.Recovery())
e.GET("/", func(c *gin.Context) {
c.JSON(
http.StatusOK,
gin.H{
"code": http.StatusOK,
"error": "Welcome server 02",
},
)
})
return e
}
func main() {
server01 := &http.Server{
Addr: ":8080",
Handler: router01(),
ReadTimeout: 5 * time.Second,
WriteTimeout: 10 * time.Second,
}
server02 := &http.Server{
Addr: ":8081",
Handler: router02(),
ReadTimeout: 5 * time.Second,
WriteTimeout: 10 * time.Second,
}
g.Go(func() error {
return server01.ListenAndServe()
})
g.Go(func() error {
return server02.ListenAndServe()
})
if err := g.Wait(); err != nil {
log.Fatal(err)
}
}
HTTP2 服务器推送
http.Pusher 仅仅被 go1.8+ 支持。 在 golang 官方博客 中查看详细信息。
package main
import (
"html/template"
"log"
"github.com/gin-gonic/gin"
)
var html = template.Must(template.New("https").Parse(`
<html>
<head>
<title>Https Test</title>
<script src="/assets/app.js"></script>
</head>
<body>
<h1 style="color:red;">Welcome, Ginner!</h1>
</body>
</html>
`))
func main() {
r := gin.Default()
r.Static("/assets", "./assets")
r.SetHTMLTemplate(html)
r.GET("/", func(c *gin.Context) {
if pusher := c.Writer.Pusher(); pusher != nil {
// 使用 pusher.Push() 去进行服务器推送
if err := pusher.Push("/assets/app.js", nil); err != nil {
log.Printf("Failed to push: %v", err)
}
}
c.HTML(200, "https", gin.H{
"status": "success",
})
})
// 监听并服务于 https://127.0.0.1:8080
r.RunTLS(":8080", "./testdata/server.pem", "./testdata/server.key")
}
测试
net/http/httptest
包是 HTTP 测试的首选方式。
package main
func setupRouter() *gin.Engine {
r := gin.Default()
r.GET("/ping", func(c *gin.Context) {
c.String(200, "pong")
})
return r
}
func main() {
r := setupRouter()
r.Run(":8080")
}
测试上面代码的示例:
package main
import (
"net/http"
"net/http/httptest"
"testing"
"github.com/stretchr/testify/assert"
)
func TestPingRoute(t *testing.T) {
router := setupRouter()
w := httptest.NewRecorder()
req, _ := http.NewRequest("GET", "/ping", nil)
router.ServeHTTP(w, req)
assert.Equal(t, 200, w.Code)
assert.Equal(t, "pong", w.Body.String())
}
WEBSOKECT
package main
import (
"github.com/gin-gonic/gin"
"github.com/gorilla/websocket"
"net/http"
)
var upGrader = websocket.Upgrader{
CheckOrigin: func (r *http.Request) bool {
return true
},
}
//webSocket请求ping 返回pong
func ping(c *gin.Context) {
//升级get请求为webSocket协议
ws, err := upGrader.Upgrade(c.Writer, c.Request, nil)
if err != nil {
return
}
defer ws.Close()
//读取ws中的数据,一定要,单独write会报错
mt, message, err := ws.ReadMessage()
if err != nil {
return
}
// 一次read多次send
for {
message = []byte("test")
//写入ws数据
err = ws.WriteMessage(mt, message)
if err != nil {
break
}
time.Sleep(time.Second)
}
}
func main() {
bindAddress := "localhost:2303"
r := gin.Default()
r.GET("/ping", ping)
r.Run(bindAddress)
}
错误自定义
package main
import (
"github.com/gin-gonic/gin"
)
func MyRecover(c *gin.Context){
defer func() {
if err:=recover();err!=nil{ //err不等于零值,说明发生了异常
c.AbortWithStatusJSON(200,gin.H{"mes":"500"})
return
}
}()
c.Next()
}
func RouteNotFound(c *gin.Context) {
c.JSON(200,gin.H{"mes":404})
c.Abort()
}
func MethodNotFound(c *gin.Context) {
c.JSON(200,gin.H{"mes":405})
c.Abort()
}
func main() {
r := gin.New()
r.NoRoute(RouteNotFound) //404
r.NoMethod(MethodNotFound)//405
r.GET("/ping", MyRecover,func(c *gin.Context) {
a:= []string{"1","2","3"}
c.String(200,a[3])
})
r.Run() // 在 0.0.0.0:8080 上监听并服务
}
跨域
func Cors() gin.HandlerFunc {
return func(c *gin.Context) {
c.Header("Access-Control-Allow-Origin", c.GetHeader("Origin")) // 允许的请求源
c.Header("Access-Control-Allow-Headers", "Token,SessionId,Content-Type") // 后端可以拿到跨域请求的header
c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS") // 允许的请求方法
c.Header("Access-Control-Allow-Credentials", "true") // 是否允许携带身份凭证
// 能够让客户端的js读取到Header
c.Header("Access-Control-Expose-Headers", "X-Powered-By,xxx")
// 表明在xxx秒内,不需要再发送预检验请求,可以缓存该结果
c.Header("Access-Control-Max-Age", "3600")
//如果method是OPTIONS,直接返回成功
if c.Request.Method == "OPTIONS" {
c.AbortWithStatusJSON(http.StatusOK, "Options Request!")
return
}
// 处理请求
c.Next()
}
}