Perguntas Frequentes
Perguntas Gerais
Como habilito o live reload durante o desenvolvimento?
Use Air para recarregamento automático em tempo real durante o desenvolvimento. O Air monitora seus arquivos e reconstrói/reinicia sua aplicação quando mudanças são detectadas.
Instalação:
go install github.com/air-verse/air@latestConfiguração:
Crie um arquivo de configuração .air.toml na raiz do seu projeto:
air initEm seguida, execute air no diretório do seu projeto em vez de go run:
airO Air monitorará seus arquivos .go e automaticamente reconstruirá/reiniciará sua aplicação Gin quando houver mudanças. Veja a documentação do Air para opções de configuração.
Como lidar com CORS no Gin?
Use o middleware oficial gin-contrib/cors:
package main
import ( "time"
"github.com/gin-contrib/cors" "github.com/gin-gonic/gin")
func main() { r := gin.Default()
// Default CORS configuration r.Use(cors.Default())
// Or customize CORS settings r.Use(cors.New(cors.Config{ AllowOrigins: []string{"https://example.com"}, AllowMethods: []string{"GET", "POST", "PUT", "DELETE"}, AllowHeaders: []string{"Origin", "Content-Type", "Authorization"}, ExposeHeaders: []string{"Content-Length"}, AllowCredentials: true, MaxAge: 12 * time.Hour, }))
r.GET("/ping", func(c *gin.Context) { c.JSON(200, gin.H{"message": "pong"}) })
r.Run()}Para uma visão geral completa de segurança, veja Melhores práticas de segurança.
Como servir arquivos estáticos?
Use Static() ou StaticFS() para servir arquivos estáticos:
func main() { r := gin.Default()
// Serve files from ./assets directory at /assets/* r.Static("/assets", "./assets")
// Serve a single file r.StaticFile("/favicon.ico", "./resources/favicon.ico")
// Serve from embedded filesystem (Go 1.16+) r.StaticFS("/public", http.FS(embedFS))
r.Run()}Veja Servindo dados de arquivo para mais detalhes.
Como lidar com upload de arquivos?
Use FormFile() para arquivos únicos ou MultipartForm() para múltiplos arquivos:
// Single file uploadr.POST("/upload", func(c *gin.Context) { file, _ := c.FormFile("file") c.SaveUploadedFile(file, "./uploads/"+file.Filename) c.String(200, "File %s uploaded successfully", file.Filename)})
// Multiple files uploadr.POST("/upload-multiple", func(c *gin.Context) { form, _ := c.MultipartForm() files := form.File["files"]
for _, file := range files { c.SaveUploadedFile(file, "./uploads/"+file.Filename) } c.String(200, "%d files uploaded", len(files))})Veja a documentação de Upload de arquivos para mais detalhes.
Como implementar autenticação com JWT?
Use gin-contrib/jwt ou implemente middleware customizado. Aqui está um exemplo mínimo:
package main
import ( "net/http" "time"
"github.com/gin-gonic/gin" "github.com/golang-jwt/jwt/v5")
var jwtSecret = []byte("your-secret-key")
type Claims struct { Username string `json:"username"` jwt.RegisteredClaims}
func AuthMiddleware() gin.HandlerFunc { return func(c *gin.Context) { tokenString := c.GetHeader("Authorization") if tokenString == "" { c.JSON(http.StatusUnauthorized, gin.H{"error": "Missing authorization token"}) c.Abort() return }
// Remove "Bearer " prefix if present if len(tokenString) > 7 && tokenString[:7] == "Bearer " { tokenString = tokenString[7:] }
token, err := jwt.ParseWithClaims(tokenString, &Claims{}, func(token *jwt.Token) (interface{}, error) { return jwtSecret, nil })
if err != nil || !token.Valid { c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid token"}) c.Abort() return }
if claims, ok := token.Claims.(*Claims); ok { c.Set("username", claims.Username) c.Next() } }}Para autenticação baseada em sessão, veja Gerenciamento de sessões.
Como configurar logging de requisições?
O Gin inclui um middleware de logger padrão via gin.Default(). Para logging JSON estruturado em produção, veja Logging estruturado.
Para customização básica de log:
r := gin.New()r.Use(gin.LoggerWithConfig(gin.LoggerConfig{ SkipPaths: []string{"/healthz"},}))r.Use(gin.Recovery())Veja a seção Logging para todas as opções incluindo formatos customizados, saída para arquivo e omissão de query strings.
Como lidar com desligamento gracioso?
Veja Reinicialização ou parada graciosa para um guia completo com exemplos de código.
Por que estou recebendo “404 Not Found” em vez de “405 Method Not Allowed”?
Por padrão, o Gin retorna 404 para rotas que não suportam o método HTTP requisitado. Defina HandleMethodNotAllowed = true para retornar 405 em vez disso:
r := gin.Default()r.HandleMethodNotAllowed = true
r.GET("/ping", func(c *gin.Context) { c.JSON(200, gin.H{"message": "pong"})})
r.Run()$ curl -X POST localhost:8080/ping
HTTP/1.1 405 Method Not AllowedAllow: GETComo vincular parâmetros de query e dados POST juntos?
Use ShouldBind() que seleciona automaticamente o binding baseado no tipo de conteúdo:
type User struct { Name string `form:"name" json:"name"` Email string `form:"email" json:"email"` Page int `form:"page"`}
r.POST("/user", func(c *gin.Context) { var user User if err := c.ShouldBind(&user); err != nil { c.JSON(400, gin.H{"error": err.Error()}) return } c.JSON(200, user)})Veja a seção Binding para todas as opções de binding.
Como validar dados da requisição?
O Gin usa go-playground/validator para validação. Adicione tags de validação às suas structs:
type User struct { Name string `json:"name" binding:"required,min=3,max=50"` Email string `json:"email" binding:"required,email"` Age int `json:"age" binding:"gte=0,lte=130"`}
r.POST("/user", func(c *gin.Context) { var user User if err := c.ShouldBindJSON(&user); err != nil { c.JSON(400, gin.H{"error": err.Error()}) return } c.JSON(200, gin.H{"message": "User is valid"})})Veja Binding e validação para validadores customizados e uso avançado.
Como executar o Gin em modo de produção?
Defina a variável de ambiente GIN_MODE como release:
export GIN_MODE=release# orGIN_MODE=release ./your-appOu defina programaticamente:
gin.SetMode(gin.ReleaseMode)O modo release desabilita o logging de debug e melhora o desempenho.
Como lidar com conexões de banco de dados com o Gin?
Veja Integração com banco de dados para um guia completo cobrindo database/sql, GORM, pool de conexões e padrões de injeção de dependência.
Como testar handlers do Gin?
Use net/http/httptest para testar suas rotas:
func TestPingRoute(t *testing.T) { router := gin.Default() router.GET("/ping", func(c *gin.Context) { c.JSON(200, gin.H{"message": "pong"}) })
w := httptest.NewRecorder() req, _ := http.NewRequest("GET", "/ping", nil) router.ServeHTTP(w, req)
assert.Equal(t, 200, w.Code) assert.Contains(t, w.Body.String(), "pong")}Veja a documentação de Testes para mais exemplos.
Perguntas sobre Desempenho
Como otimizar o Gin para alto tráfego?
- Use o modo Release: Defina
GIN_MODE=release - Desabilite middleware desnecessário: Use apenas o que você precisa
- Use
gin.New()em vez degin.Default()para controle manual de middleware - Pool de conexões: Configure pools de conexão do banco de dados (veja Integração com banco de dados)
- Cache: Implemente cache para dados acessados frequentemente
- Balanceamento de carga: Use proxy reverso (nginx, HAProxy)
- Profiling: Use o pprof do Go para identificar gargalos
- Monitoramento: Configure métricas e monitoramento para acompanhar o desempenho
O Gin está pronto para produção?
Sim. O Gin é usado em produção por muitas empresas e foi testado em batalha em escala. Veja Usuários para exemplos de projetos usando Gin em produção.
Solução de Problemas
Por que meus parâmetros de rota não estão funcionando?
Certifique-se de que os parâmetros de rota usam a sintaxe : e são extraídos corretamente:
// Correctr.GET("/user/:id", func(c *gin.Context) { id := c.Param("id") c.String(200, "User ID: %s", id)})
// Not: /user/{id} or /user/<id>Veja Parâmetros no caminho para detalhes.
Por que meu middleware não está executando?
O middleware deve ser registrado antes das rotas ou grupos de rotas:
// Correct orderr := gin.New()r.Use(MyMiddleware()) // Register middleware firstr.GET("/ping", handler) // Then routes
// For route groupsauth := r.Group("/admin")auth.Use(AuthMiddleware()) // Middleware for this group{ auth.GET("/dashboard", handler)}Veja Usando middleware para detalhes.
Por que o binding de requisição está falhando?
Razões comuns:
- Tags de binding ausentes: Adicione tags
json:"field"ouform:"field" - Content-Type incompatível: Certifique-se de que o cliente envia o header Content-Type correto
- Erros de validação: Verifique as tags de validação e requisitos
- Campos não exportados: Apenas campos exportados (com letra maiúscula) da struct são vinculados
type User struct { Name string `json:"name" binding:"required"` // ✓ Correct Email string `json:"email"` // ✓ Correct age int `json:"age"` // ✗ Won't bind (unexported)}Veja Binding e validação para detalhes.