Uncle Sam's blog
Published: 2025-07-21 (a year ago)
关于

Uncle Sam's Blog Restructuring Journey: A Full-Stack Upgrade from Django to Gin + Vue.ts

Introduction: The Metamorphosis from Python to Go

After months of refactoring and optimizing, my blog has finally completed a gorgeous turnaround from Django to the Go tech stack!

I remember that in early 2024, I was still maintaining a Django-based blogging system - originally an open-source project called "Maple Knows", and the second version was developed on DRF+Vue.js after understanding the first version. However, the architecture of dynamically typed languages is used in both the front and backend, which makes subsequent maintenance gradually difficult and function iterations become more and more slow.

coincided with a full shift to Golang in the company's technology stack, and I decided to take this opportunity to completely refactor the project in Go.

Today, the newly upgraded Uncle Sam blog system has been officially launched. This is a modern front-end and back-end separation architecture based on Gin + Vue.ts + MySQL + Redis + ES + COS, which not only achieves a leapfrog improvement in performance, but also qualitatively improves scalability and maintainability.

New Architecture Technology Stack

Backend Engine: Gin High Performance Framework

go Copy
Gin route definition and middleware usage example
func main() {
    r := gin. Default()
    
    Integrated Redis caching middleware (reduces database access pressure)
    r.Use(redisMiddleware())
    
    Article Routing Group (API Versioning Management)
    articleGroup := r.Group("/api/v1/articles")
    {
        articleGroup.GET("", articleHandler.List) // Public Access: List of articles
        articleGroup.POST("", authMiddleware(), articleHandler.Create) // Authentication required: Create an article
        articleGroup.GET("/:id", articleHandler.Get) // Public access: Individual article details
    }
    
    Start the service (listen on port 8080)
    if err := r.Run(":8080"); err != nil {
        log. Fatalf("Service Start Failed: %v", err)
    }
}

Core Reasons for Choosing Gin:

  • Performance crushing: 5-10 times faster request processing power than Django, especially in high-concurrency scenarios
  • Extremely lightweight: The core framework is less than 5MB, and the deployment package is smaller and starts faster
  • Middleware Ecosystem: Out-of-the-box authentication, current limiting, caching, and other modules for easy functional expansion

Data storage layer: Multi-engine collaboration

  • MySQL: Responsible for persistent storage of structured data, such as article content, user information, comment data, and other core business data
  • Redis
    • Hot article caching (reduces database access pressure)
    • User session state management (replaces Django's session mechanism)
    • Interface frequency limit counter (to prevent malicious requests)
  • Elasticsearch
    • Full-text search engine (supports complex search requirements)
    • Intelligent recommendations for related articles (based on content similarity)
    • Efficient content filtering (filtering by tags, categories, time, etc.)

Front-end architecture: Vue3 + TypeScript

vue Copy
<template>
  <div class="article-detail">
    <h1>{{ article.title }}</h1>
    <div class="content"></div>
    <div class="comments">
      
    </div>
  </div>
</template>

Front-end Technology Highlights:

  • 'md-editor-v3' is used for efficient rendering and previewing of Markdown content
  • TypeScript strong type constraints, reducing runtime errors by more than 70%
  • Responsive layout design that performs well on mobile, tablet, and PC

Cloud Service Integration: Tencent Cloud COS

go Copy
Image upload to COS core logic
func UploadToCOS(file *multipart. FileHeader) (string, error) {
    Initialize the COS client
    client := cos. NewClient(bucketURL, &cos. BaseURL{BucketURL: bucketDomain})
    
    Open the upload file
    f, err := file. Open()
    if err != nil {
        return "", fmt. Errorf("File opened failed: %v", err)
    }
    defer f.Close()
    
    Generate unique file names (to avoid conflicts)
    key := fmt. Sprintf("images/%d-%s", time. Now(). UnixMicro(), file. Filename)
    
    Upload files to COS
    _, err = client. Object.Put(context. Background(), key, f, nil)
    if err != nil {
        return "", fmt. Errorf("COS upload failed: %v", err)
    }
    
    Returns the CDN acceleration address
    return fmt. Sprintf("%s/%s", cdnDomain, key), nil
}

Cloud Storage Advantages:

  • Separation of static resources from application services (reducing server storage pressure)
  • Global CDN node acceleration (3-5x faster image loading)
  • Automatic media processing (supports image compression, format conversion, watermark addition)

Core function upgrades

Search systems built on Elasticsearch are a qualitative leap forward:

  • Response speed down from seconds to milliseconds (results returned in an average of 150ms)
  • Support mixed Chinese and English word segmentation (accurately identify multilingual content)
  • Keyword highlighting (quickly target matching content)
  • Search suggestions (auto-complete possible keywords as you type)

2. Smart caching policies

Multi-level caching mechanism design:

  • Hot articles (top 20% of visits) cached for 15 minutes (dynamically adjusted)
  • Daily Top Leaderboard cache for 1 hour (updated regularly)
  • Permanent caching of categories/tags list (actively invalidated on update)
  • Local caching of home content (independent control of head banner and bottom recommendation)

3. Third-party login integrations

go Copy
GitHub OAuth2 login callback handling
func GitHubLoginCallback(c *gin. Context) {
    // 1. Redeem the authorization code for an access token
    code := c.Query("code")
    token, err := githubOAuth.Exchange(context. Background(), code)
    if err != nil {
        c.JSON(http. StatusBadRequest, gin. H{"error": "authorization failed"})
        return
    }
    
    // 2. Get user information
    userInfo, err := githubOAuth.GetUserInfo(token. AccessToken)
    if err != nil {
        c.JSON(http. StatusInternalServerError, gin. H{"error": "Failed to obtain user information"})
        return
    }
    
    // 3. Create or update local users
    user := models. FindOrCreateUser(userInfo)
    
    // 4. Generate JWT token (valid for 7 days)
    jwtToken, err := generateJWT(user.ID, 7*24*time. Hour)
    if err != nil {
        c.JSON(http. StatusInternalServerError, gin. H{"error": "Token generation failed"})
        return
    }
    
    // 5. Skip to home page (carry token)
    c.Redirect(http. StatusFound, fmt. Sprintf("/?token=%s", jwtToken))
}

Supported and planned login methods:

  • Online: GitHub login (seamless integration into the open source ecosystem)
  • Live: Microsoft Sign-In (Windows Full Series Productivity)
  • Under development: WeChat login (covering a wider user group) // Depending on the situation, it needs to be recorded, which is too troublesome

4. Large model integration

javascript Copy
AI writing assistant interaction logic
const askAI = async (question: string) => {
    Displays loading status
    isLoading.value = true
    aiResponse.value = ''
    
    try {
        Initiate a streaming request
        const res = await fetch('/api/ai/ask', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ question, context: currentDraft.value })
        })
        
        Handle streaming responses
        const reader = res.body?. getReader()
        const decoder = new TextDecoder()
        
        while (true) {
            const { done, value } = await reader.read()
            if (done) break
            
            Stitch together AI-replied content in real-time
            aiResponse.value += decoder.decode(value, { stream: true })
        }
    } catch (err) {
        aiResponse.value = 'AI service is temporarily unavailable, please try again later'
    } finally {
        isLoading.value = false
    }
}

AI Features in Action:

  • Intelligent summaries of article content (automatically generate introductions within 200 words)
  • Automatic review of comment content (identification of spam comments and sensitive words)
  • Writing assistant real-time suggestions (wording optimization, paragraph restructuring suggestions available)

Performance optimization results

Indicators Legacy (Django) New edition (Gin) Increase
HomeAverage load time 850ms 220ms 74%
Search response time 1200ms 150ms 87%
Concurrent processing capacity 150 req/s 3200 req/s 20x
Server memory usage 420MB 55MB 87%
Single article render time 350ms 60ms 83%

Development Challenges and Solutions

Cross-domain problem handling

Cross-domain solution under the front-end and back-end separation architecture:

go Copy
Refined CORS middleware implementation
func CORSMiddleware() gin. HandlerFunc {
    return func(c *gin. Context) {
        Allow domain names (production environment restriction source)
        origin := c.Request.Header.Get("Origin")
        if allowOrigin(origin) {
            c.Writer.Header(). Set("Access-Control-Allow-Origin", origin)
        }
        
        Allowed request methods
        c.Writer.Header(). Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
        
        Allowed request headers
        c.Writer.Header(). Set("Access-Control-Allow-Headers", "Origin, Content-Type, Authorization")
        
        Allow credentials (e.g. cookies)
        c.Writer.Header(). Set("Access-Control-Allow-Credentials", "true")
        
        Preflight request cache time
        c.Writer.Header(). Set("Access-Control-Max-Age", "86400")
        
        Process preflight requests
        if c.Request.Method == "OPTIONS" {
            c.AbortWithStatus(http. StatusNoContent)
            return
        }
        
        c.Next()
    }
}

Large file upload optimization

Experience optimization for image/attachment uploads:

  • Front-end shard upload (splitting large files into small 5MB chunks for parallel transfer)
  • Backend parallel write to COS (utilizing Go's goroutine concurrency processing)
  • Breakpoint resumption support (records can be restored after network interruption if the uploaded fragment is uploaded)
  • Real-time display of upload progress (push progress information via WebSocket)

High concurrency scenario response

Traffic Peak Handling Strategy:

  • Redis Bloom Filter (prevents cache penetration)
  • Gin server connection pool tuning (increase the concurrency processing limit)
  • CDN acceleration for static resources (reduces the pressure on the origin server)
  • Dynamic scaling configuration (auto-scaling based on CPU/memory usage)

Future Planning

Technology Evolution Route

Short-term plan (within 3 months):

  • Multilingual support (automatic switching between Chinese and English)
  • Improve content statistics (visits, sources, user behavior)

Medium-term target (within 6 months):

  • Deep AI integration (intelligent recommendation engine, automatic image matching)
  • PWA support (offline access to core features)

Long-term planning (within 1 year):

  • WeChat ecological integration (scan code login, official account synchronization, mini program version)
  • Community interaction features (like, favorite, follow author)

Conclusion: A new starting point, a new journey

This refactoring is not only a replacement of the technology stack, but also a complete optimization of the blog system architecture. The transition from dynamic to static types significantly improves code quality and maintainability. The evolution from monolithic frames to front-end separation makes the system more flexible and scalable.

At present, the new blog system is running stably in production, welcome to visit the experience:

The pace of technology upgrades doesn't stop, and I'll focus on improving AI capabilities and multilingual support. If you have any suggestions or find problems, please leave a message in the comment area - the progress of technology always comes from continuous practice and feedback!