一个具体的例子,用 ruby 写一个一个 自动生成 图片压缩的服务, 然后 转换成 go
require 'sinatra'
require 'open-uri'
require 'rmagick'
require 'time'
# Initialize cache
$image_cache = {}
# Cleanup task to remove stale cache entries
Thread.new do
  loop do
    sleep 8 * 60 * 60  # Sleep for 24 hours
    current_time = Time.now
    $image_cache.delete_if do |url, entry|
      current_time - entry[:last_accessed] > 24 * 60 * 60
    end
  end
end
get '/' do
  # Get the URL parameter
  url = params['url']
  # Ensure the URL is provided
  halt 400, 'URL parameter is missing' if url.nil?
  # Check cache for the image
  if $image_cache.key?(url)
    entry = $image_cache[url]
    entry[:last_accessed] = Time.now
    content_type 'image/jpeg'
    return entry[:image_data]
  end
  # Fetch the image from the URL
  begin
    image_data = URI.open(url).read
  rescue => e
    halt 500, "Failed to fetch image: #{e.message}"
  end
  # Read the image data using RMagick
  begin
    image = Magick::Image.from_blob(image_data).first
  rescue => e
    halt 500, "Failed to read image: #{e.message}"
  end
  # Resize the image while maintaining the aspect ratio
  begin
    resized_image = image.change_geometry("360") do |cols, rows, img|
      img.resize(cols, rows)
    end
  rescue => e
    halt 500, "Failed to resize image: #{e.message}"
  end
  # Convert the resized image to a blob
  resized_image_data = resized_image.to_blob
  begin
  # Convert the resized image to a blob
  resized_image_data = resized_image.to_blob
  rescue Magick::ImageMagickError => e
  puts "Error: #{e.message}"
  puts "Backtrace: #{e.backtrace.join("\n")}"
  end
  # Store the resized image in the cache
  $image_cache[url] = {
    image_data: resized_image_data,
    last_accessed: Time.now
  }
  # Send the resized image data to the user
  content_type 'image/jpeg'
  resized_image_data
end%
转换后的代码,
package main
import (
    "bytes"
    "fmt"
    "image"
    "image/jpeg"
    "log"
    "net/http"
    "sync"
    "time"
    "
github.com/nfnt/resize"
)
const (
    port           = 8300
    cacheCleanupInterval = 8 * time.Hour
    cacheExpirationTime  = 24 * time.Hour
)
type CacheEntry struct {
    ImageData    []byte
    LastAccessed time.Time
}
var (
    imageCache = make(map[string]*CacheEntry)
    cacheMutex sync.RWMutex
)
func main() {
    go cleanupCache()
    http.HandleFunc("/", handleRequest)
    log.Printf("Server starting on port %d", port)
    log.Fatal( http.ListenAndServe(fmt.Sprintf(":%d", port), nil))
}
func cleanupCache() {
    for {
        time.Sleep(cacheCleanupInterval)
        currentTime := time.Now()
        cacheMutex.Lock()
        for url, entry := range imageCache {
            if currentTime.Sub(entry.LastAccessed) > cacheExpirationTime {
                delete(imageCache, url)
            }
        }
        cacheMutex.Unlock()
    }
}
func handleRequest(w http.ResponseWriter, r *http.Request) {
    url := r.URL.Query().Get("url")
    if url == "" {
        http.Error(w, "URL parameter is missing", http.StatusBadRequest)
        return
    }
    cacheMutex.RLock()
    if entry, ok := imageCache[url]; ok {
        entry.LastAccessed = time.Now()
        cacheMutex.RUnlock()
        w.Header().Set("Content-Type", "image/jpeg")
        w.Write(entry.ImageData)
        return
    }
    cacheMutex.RUnlock()
    log.Printf("Fetching image: %v\n", url)
    resp, err := http.Get(url)
    if err != nil {
        http.Error(w, fmt.Sprintf("Failed to fetch image: %v", err), http.StatusInternalServerError)
        return
    }
    defer resp.Body.Close()
    img, _, err := image.Decode(resp.Body)
    if err != nil {
        http.Error(w, fmt.Sprintf("Failed to decode image: %v", err), http.StatusInternalServerError)
        return
    }
    resizedImg := resize.Resize(360, 0, img, resize.Lanczos3)
    var buf bytes.Buffer
    if err := jpeg.Encode(&buf, resizedImg, nil); err != nil {
        http.Error(w, fmt.Sprintf("Failed to encode resized image: %v", err), http.StatusInternalServerError)
        return
    }
    cacheMutex.Lock()
    imageCache[url] = &CacheEntry{
        ImageData:    buf.Bytes(),
        LastAccessed: time.Now(),
    }
    cacheMutex.Unlock()
    w.Header().Set("Content-Type", "image/jpeg")
    w.Write(buf.Bytes())
}%