Skip to content

Latest commit

 

History

History
571 lines (431 loc) · 12.4 KB

File metadata and controls

571 lines (431 loc) · 12.4 KB

FAQ (Frequently Asked Questions)

Basic Questions

How to support SSL (https)

Private Server: SSL certificate management can be implemented through frontend load balancers like Nginx, which is more efficient in terms of performance.

Cloud Service Providers: Most cloud service providers' load balancing services have built-in SSL certificate management.

Example Nginx configuration:

server {
    listen 443 ssl;
    server_name your-domain.com;
    
    ssl_certificate /path/to/cert.pem;
    ssl_certificate_key /path/to/key.pem;
    
    location / {
        proxy_pass http://localhost:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

How to support data compression and HTTP/2.0

Implement through frontend load balancers like Nginx. This approach is definitely more efficient than built-in httpsrv implementation, also conforms to operational management convenience. More importantly, it maintains httpsrv's positioning as purely concise.

Example of Nginx enabling gzip compression:

http {
    gzip on;
    gzip_vary on;
    gzip_min_length 1024;
    gzip_types text/plain text/css text/xml text/javascript
               application/x-javascript application/xml+rss
               application/json application/javascript;
}

How to get client real IP

When using reverse proxies like Nginx, you need to get the real IP from HTTP headers:

func (c BaseController) GetClientIP() string {
	// Check X-Real-IP header
	if ip := c.Request.Header.Get("X-Real-IP"); ip != "" {
		return ip
	}
	// Check X-Forwarded-For header
	if ip := c.Request.Header.Get("X-Forwarded-For"); ip != "" {
		return ip
	}
	// Default to RemoteAddr
	return c.Request.RemoteAddr
}

Development Questions

How to handle Cross-Origin Resource Sharing (CORS)

httpsrv doesn't have built-in CORS support. You can implement it through Filter:

package main

import (
	"github.com/hooto/httpsrv"
)

func CorsFilter(c *httpsrv.Controller, fc []httpsrv.Filter) {
	// Set CORS headers
	c.Response.Out.Header().Set("Access-Control-Allow-Origin", "*")
	c.Response.Out.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
	c.Response.Out.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization")
	c.Response.Out.Header().Set("Access-Control-Max-Age", "86400")
	
	// Handle OPTIONS preflight request
	if c.Request.Method == "OPTIONS" {
		c.Response.Out.WriteHeader(200)
		return
	}
	
	// Continue executing subsequent Filters
	fc[0](c, fc[1:])
}

func main() {
	// Register CORS Filter
	httpsrv.GlobalService.Filters = []httpsrv.Filter{
		CorsFilter,
	}
	
	// Register module
	httpsrv.GlobalService.HandleModule("/", NewModule())
	httpsrv.GlobalService.Start()
}

How to implement file upload

httpsrv supports standard multipart form data upload:

type FileUpload struct {
	*httpsrv.Controller
}

func (c FileUpload) UploadAction() {
	// Parse form
	if err := c.Request.ParseMultipartForm(32 << 20); err != nil {
		c.RenderError(400, "Form parsing failed")
		return
	}
	
	file, header, err := c.Request.FormFile("file")
	if err != nil {
		c.RenderError(400, "Failed to get file")
		return
	}
	defer file.Close()
	
	// Save file
	// Here uses example logic, actual project should save to specified directory
	// File information can be obtained through header
	filename := header.Filename
	filesize := header.Size
	contentType := header.Header.Get("Content-Type")
	
	c.RenderJson(map[string]interface{}{
		"status":  "success",
		"filename": filename,
		"size":     filesize,
		"type":     contentType,
	})
}

Frontend HTML form:

<form action="/file-upload/upload" method="POST" enctype="multipart/form-data">
    <input type="file" name="file" />
    <button type="submit">Upload</button>
</form>

How to handle Session

httpsrv has built-in Session support:

type Auth struct {
	*httpsrv.Controller
}

func (c Auth) LoginAction() {
	username := c.Params.Value("username")
	password := c.Params.Value("password")
	
	// Verify username and password
	if username == "admin" && password == "password" {
		// Set Session
		c.Session.Set("user_id", "12345")
		c.Session.Set("username", username)
		
		c.RenderJson(map[string]string{
			"status": "success",
			"message": "Login successful",
		})
	} else {
		c.RenderError(401, "Invalid username or password")
	}
}

func (c Auth) ProfileAction() {
	// Get Session
	userId := c.Session.Get("user_id")
	username := c.Session.Get("username")
	
	if userId == "" {
		c.RenderError(401, "Not logged in")
		return
	}
	
	c.RenderJson(map[string]interface{}{
		"user_id":  userId,
		"username": username,
	})
}

func (c Auth) LogoutAction() {
	// Clear Session
	c.Session.Clear()
	
	c.RenderJson(map[string]string{
		"status": "success",
		"message": "Logout successful",
	})
}

How to implement i18n internationalization

httpsrv supports multiple languages, can be implemented by setting Locale:

type I18nDemo struct {
	*httpsrv.Controller
}

func (c I18nDemo) IndexAction() {
	// Get language setting from request
	// Can get from URL parameters, Cookie or HTTP headers
	lang := c.Params.Value("lang")
	if lang == "" {
		lang = c.Request.Header.Get("Accept-Language")
	}
	
	messages := map[string]map[string]string{
		"zh": {
			"title": "欢迎",
			"hello": "你好,世界",
		},
		"en": {
			"title": "Welcome",
			"hello": "Hello, World",
		},
	}
	
	if msg, ok := messages[lang]; ok {
		c.RenderJson(msg)
	} else {
		c.RenderJson(messages["zh"])
	}
}

How to implement API versioning

It's recommended to implement versioning through Module paths:

func main() {
	// v1 API
	httpsrv.GlobalService.HandleModule("/api/v1", NewApiV1Module())
	
	// v2 API
	httpsrv.GlobalService.HandleModule("/api/v2", NewApiV2Module())
	
	httpsrv.GlobalService.Start()
}

// v1 module
func NewApiV1Module() *httpsrv.Module {
	mod := httpsrv.NewModule()
	mod.RegisterController(new(ApiV1Controller))
	return mod
}

// v2 module
func NewApiV2Module() *httpsrv.Module {
	mod := httpsrv.NewModule()
	mod.RegisterController(new(ApiV2Controller))
	return mod
}

Access paths:

  • v1 API: /api/v1/controller/action
  • v2 API: /api/v2/controller/action

Deployment Questions

How to configure graceful shutdown

Use signal handling to implement graceful shutdown:

package main

import (
	"os"
	"os/signal"
	"syscall"
	"github.com/hooto/httpsrv"
)

func main() {
	// Start service
	go func() {
		httpsrv.GlobalService.Start()
	}()
	
	// Wait for interrupt signal
	quit := make(chan os.Signal, 1)
	signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
	<-quit
	
	// Execute cleanup operations
	// Close database connections
	// Save cache, etc.
	
	// httpsrv will handle shutdown automatically
}

How to configure production environment configuration file

httpsrv supports multiple configuration file formats, JSON or YAML is recommended:

package main

import (
	"encoding/json"
	"io/ioutil"
	"os"
	"github.com/hooto/httpsrv"
)

type Config struct {
	HttpPort       int    `json:"http_port"`
	DatabaseURL    string `json:"database_url"`
	RedisURL       string `json:"redis_url"`
	LogLevel       string `json:"log_level"`
}

func loadConfig() (*Config, error) {
	configFile := "config.json"
	if os.Getenv("APP_ENV") == "production" {
		configFile = "config.prod.json"
	}
	
	data, err := ioutil.ReadFile(configFile)
	if err != nil {
		return nil, err
	}
	
	var config Config
	if err := json.Unmarshal(data, &config); err != nil {
		return nil, err
	}
	
	return &config, nil
}

func main() {
	config, err := loadConfig()
	if err != nil {
		panic(err)
	}
	
	httpsrv.GlobalService.Config.HttpPort = uint16(config.HttpPort)
	
	// Use other configuration items to connect to database, Redis, etc.
	
	httpsrv.GlobalService.Start()
}

How to implement health check endpoint

Create a dedicated health check module:

type HealthCheck struct {
	*httpsrv.Controller
}

func (c HealthCheck) IndexAction() {
	// Check database connection
	dbOK := checkDatabase()
	
	// Check Redis connection
	redisOK := checkRedis()
	
	status := "ok"
	if !dbOK || !redisOK {
		status = "error"
		c.Response.Out.WriteHeader(503)
	}
	
	c.RenderJson(map[string]interface{}{
		"status":   status,
		"database": dbOK,
		"redis":    redisOK,
	})
}

func NewHealthCheckModule() *httpsrv.Module {
	mod := httpsrv.NewModule()
	mod.RegisterController(new(HealthCheck))
	return mod
}

func main() {
	// Register health check module
	httpsrv.GlobalService.HandleModule("/health", NewHealthCheckModule())
	
	// Register other modules
	httpsrv.GlobalService.HandleModule("/", NewMainModule())
	
	httpsrv.GlobalService.Start()
}

Performance Questions

How to optimize static file serving

It's recommended to use dedicated static file servers:

func main() {
	// Use CDN or dedicated static file service
	// httpsrv only handles dynamic content
	
	httpsrv.GlobalService.HandleModule("/api", NewApiModule())
	httpsrv.GlobalService.Start()
}

Or use Nginx to serve static files:

server {
    location /static/ {
        root /path/to/static/files;
        expires 30d;
        add_header Cache-Control "public, immutable";
    }
    
    location / {
        proxy_pass http://localhost:8080;
    }
}

How to implement caching

httpsrv doesn't have built-in caching. Redis or in-memory cache is recommended:

import "github.com/lynkdb/redisgo"

var redisClient *redisgo.RedisClient

func main() {
	// Initialize Redis client
	redisClient = redisgo.NewClient(&redisgo.Config{
		Addr: "localhost:6379",
	})
	
	httpsrv.GlobalService.Start()
}

type CacheDemo struct {
	*httpsrv.Controller
}

func (c CacheDemo) GetDataAction() {
	key := "data_key"
	
	// Try to get from cache
	data, err := redisClient.Get(key).Result()
	if err == nil && data != "" {
		c.Response.Out.Header().Set("X-Cache", "HIT")
		c.RenderString(data)
		return
	}
	
	// Cache miss, get from database
	dbData := fetchDataFromDB()
	
	// Set cache
	redisClient.Set(key, dbData, 5*time.Minute)
	
	c.Response.Out.Header().Set("X-Cache", "MISS")
	c.RenderString(dbData)
}

Common Errors

Action method not recognized by routing

Make sure Action method ends with Action():

// ❌ Wrong
func (c User) Login() {
	// ...
}

// ✅ Correct
func (c User) LoginAction() {
	// ...
}

Static file 404 error

Check if static file path configuration is correct:

func NewModule() *httpsrv.Module {
	mod := httpsrv.NewModule()
	
	// Make sure local file path exists
	mod.RegisterFileServer("/assets", "./static", nil)
	
	return mod
}

// Access URL: /assets/css/style.css
// Corresponds to local file: ./static/css/style.css

Template file not found

Check if template path is set correctly:

func NewModule() *httpsrv.Module {
	mod := httpsrv.NewModule("ui")
	
	// Make sure template path is set correctly
	mod.SetTemplatePath("./views/ui")
	
	return mod
}

// If Controller is User and Action is Index
// System will look for: ./views/ui/user/index.tpl

Use Cases

Are there use cases

httpsrv as a personal project has been applied to certain industry software since 2013:

  • SysInner.com uses httpsrv to implement all API and Web modules
  • Provides API implementation in a certain hundred-billion-level advertising system, stable and efficient in handling data collection and index queries
  • Provides API implementation in a certain PB-level object storage service, with stable and reliable stability and memory usage in high-traffic IO read/write scenarios
  • Provides API implementations including user systems, message systems, interaction systems, etc., in multiple satellite TV gala live interaction events, running efficiently without exceptions in billions of PV and millions of UV scenarios, with comprehensive response time within 50 milliseconds (Environment note: 60 interface server 2-core cloud hosts, 6 database 4-core high-speed SSD cloud hosts, cluster load peak less than 5%, traffic implemented through cloud service provider load balancer export)

Other Questions

Still haven't solved the problem?

If the above information doesn't help, you can send the problem to evorui at gmail dot com.

How to contribute code

Pull Requests or Bug reports are welcome, please visit: https://github.com/hooto/httpsrv

How to get the latest updates

go get -u github.com/hooto/httpsrv