用golang的map實現短鏈接服務的核心是通過兩個map維護長短鏈雙向映射,配合自增id生成base62短串,并通過http接口提供生成和跳轉功能。1. 使用shorttolong和longtoshort兩個map實現雙向映射,避免重復生成相同短鏈;2. 通過自增id結合base62編碼生成唯一短標識符;3. 利用net/http庫創建shorten接口接收長鏈接生成短鏈、redirect接口根據短鏈跳轉原鏈接;4. 數據存儲于內存適合原型開發,但需注意重啟丟失、并發安全及沖突風險。
短鏈接服務的核心是將一個長 URL 映射成一個簡短的字符串,用戶訪問這個短串就能跳轉到原始地址。如果你只是想快速實現一個基礎版本,用 golang 的 map 做內存存儲是一個簡單又直接的辦法。
下面我們就來看看怎么一步步用 Golang + map 實現一個最簡單的短鏈接服務。
1. 設計數據結構和映射關系
我們使用兩個 map 來保存長短鏈接之間的雙向映射:
立即學習“go語言免費學習筆記(深入)”;
- 一個用于短鏈 → 長鏈(供跳轉時查找)
- 一個用于長鏈 → 短鏈(避免重復生成)
var shortToLong = make(map[string]string) var longToShort = make(map[string]string)
這樣設計的好處是,當用戶提交相同的長鏈接時,我們可以直接返回之前生成的短鏈接,而不是每次都生成新的。
2. 生成短鏈接標識符
短鏈接的關鍵在于生成一個唯一的、較短的字符串作為標識。常見做法是使用 Base62 編碼(0-9a-zA-Z),也可以結合遞增 ID 或隨機生成。
這里我們采用一個簡單的自增 ID 方式,每次生成后轉換為 Base62:
func generateShortKey(id int) string { const base62 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" result := "" for id > 0 { id-- result = string(base62[id%62]) + result id /= 62 } return result }
比如 ID=1 會生成 “a”,ID=10000 會生成 “27g”,足夠簡潔且不易沖突。
3. 處理請求邏輯
我們使用 Go 的標準庫 net/http 搭建一個簡單的 HTTP 服務,包含兩個接口:
- /shorten:接收長鏈接,返回短鏈接
- /{key}:根據短鏈接 key 跳轉到原鏈接
接口一:生成短鏈接
var counter = 1 func shortenHandler(w http.ResponseWriter, r *http.Request) { longURL := r.URL.Query().Get("url") if longURL == "" { http.Error(w, "Missing 'url' parameter", http.StatusBadRequest) return } if short, exists := longToShort[longURL]; exists { fmt.Fprintf(w, "Short URL: http://localhost:8080/%sn", short) return } short := generateShortKey(counter) counter++ shortToLong[short] = longURL longToShort[longURL] = short fmt.Fprintf(w, "Short URL: http://localhost:8080/%sn", short) }
接口二:跳轉處理
func redirectHandler(w http.ResponseWriter, r *http.Request) { parts := strings.Split(r.URL.Path, "/") if len(parts) < 2 || parts[1] == "" { http.Error(w, "Invalid short URL", http.StatusBadRequest) return } key := parts[1] if longURL, exists := shortToLong[key]; exists { http.Redirect(w, r, longURL, http.StatusFound) } else { http.NotFound(w, r) } }
然后注冊路由并啟動服務:
func main() { http.HandleFunc("/shorten", shortenHandler) http.HandleFunc("/", redirectHandler) fmt.Println("Starting server at :8080") if err := http.ListenAndServe(":8080", nil); err != nil { log.Fatal(err) } }
4. 測試一下
-
生成短鏈接:
curl "http://localhost:8080/shorten?url=https://example.com/really-long-path?query=abc"
-
訪問短鏈接跳轉:
curl -v http://localhost:8080/a
注意事項和優化空間
雖然上面的方法已經能跑起來,但還是有些需要注意的地方:
- 重啟數據丟失:因為數據存在內存里,程序重啟就會清空。如果要持久化,可以考慮加個文件或數據庫寫入。
- 并發安全問題:多個請求同時操作 map 可能會有競態條件??梢杂?sync.Mutex 或者換成 sync.Map。
- 短鏈沖突風險:如果使用隨機生成而不是自增 ID,需要檢查是否已存在該 key。
- 性能限制:內存存儲適合小規模使用,如果數據量大了就需要上 redis 這樣的緩存系統。
基本上就這些。用 map 實現短鏈接服務雖然簡單,但很適合練手或做原型開發。等你熟悉流程后,再擴展功能、換存儲方式都不難。