17370845950

如何使用Golang实现URL短链接服务_生成短链接并进行跳转
短链接服务用Base62编码自增ID实现唯一无碰撞映射,内存map存储键值对,HTTP 302重定向跳转,支持高并发需sync.RWMutex保护。

核心思路:用哈希+映射表实现短链接生成与跳转

URL短链接服务本质是将长URL映射为短字符串(如 abc123),用户访问短链接时,服务查表重定向到原始URL。Golang 实现的关键在于:唯一性保证、高效查询、避免碰撞、支持高并发。不需要复杂数据库,用内存 map + 持久化(如 Redis 或 BoltDB)即可起步。

生成短链接:Base62 编码 + 自增ID 或哈希去重

推荐使用「自增ID转 Base62」方式,简单、有序、无碰撞、易扩展。Base62(0–9 + a–z + A–Z)比 Base64 更适合 URL,不包含 +/= 等需编码的字符。

  • 维护一个全局递增的整数 ID(可用原子操作或数据库自增字段)
  • 将 ID 转为 Base62 字符串(例如 ID=12345 → "vj3")
  • vj3 → https://example.com/very/long/path 存入映射表(map 或存储)
  • 返回完整短链接,如 https://s.co/vj3

若需支持分布式,可用 Snowflake ID 或 Redis INCR + 前缀隔离;若坚持哈希(如 MD5 取前6位),务必加碰撞检测和重试逻辑。

跳转逻辑:HTTP 302 重定向 + 路由匹配

收到请求如 GET /vj3 时,提取路径段 vj3,查表获取原始 URL,返回 302 临时重定向响应:

  • http.HandleFuncgorilla/mux 定义通配路由,如 /{code}
  • 根据 code 查询映射表(注意并发安全,用 sync.RWMutex 保护 map)
  • 查到则调用 http.Redirect(w, r, targetURL, http.StatusFound)
  • 查不到返回 404,可加日志或统计失败请求

基础可运行示例(内存版,含 Base62 转换)

以下代码可直接保存为 main.go 运行,访问 http://localhost:8080/api/shorten 提交长链接,再访问 http://localhost:8080/{code} 即跳转:

// Base62 字符集
const base62 = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"

func toBase62(n int64) string {
    if n == 0 {
        return "0"
    }
    var result []byte
    for n > 0 {
        result = append(result, base62[n%62])
        n /= 62
    }
    // 反转字节切片
    for i, j := 0, len(result)-1; i < j; i, j = i+1, j-1 {
        result[i], result[j] = result[j], result[i]
    }
    return string(result)
}

var (
    mu     sync.RWMutex
    store  = make(map[string]string) // code → long URL
    nextID int64 = 1
)

func shortenHandler(w http.ResponseWriter, r *http.Request) {
    if r.Method != "POST" {
        http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
        return
    }
    longURL := r.FormValue("url")
    if longURL == "" {
        http.Error(w, "Missing 'url' parameter", http.StatusBadRequest)
        return
    }

    mu.Lock()
    code := toBase62(nextID)
    nextID++
    store[code] = longURL
    mu.Unlock()

    json.NewEncoder(w).Encode(map[string]string{"short": "http://localhost:8080/" + code})
}

func redirectHandler(w http.ResponseWriter, r *http.Request) {
    code := strings.TrimPrefix(r.URL.Path, "/")
    mu.RLock()
    longURL, ok := store[code]
    mu.RUnlock()

    if !ok {
        http.NotFound(w, r)
        return
    }
    http.Redirect(w, r, longURL, http.StatusFound)
}

func main() {
    http.HandleFunc("/api/shorten", shortenHandler)
    http.HandleFunc("/", redirectHandler)
    fmt.Println("Server running on :8080")
    http.ListenAndServe(":8080", nil)
}

该版本轻量、无依赖,适合学习和原型验证。上线前建议替换为 Redis 存储、增加 HTTPS、限流、防刷、自定义短码、过期时间等能力。