章節
使用Go語言開發一個短連結服務:一、基本原理
使用Go語言開發一個短連結服務:二、架構設計
使用Go語言開發一個短連結服務:三、專案目錄結構設計
使用Go語言開發一個短連結服務:四、生成code演算法
使用Go語言開發一個短連結服務:五、新增和獲取短連結
使用Go語言開發一個短連結服務:六、連結跳轉
原始碼:https://gitee.com/alxps/short_link
透過這個專案,你可以學到:
- 短連結原理
- Golang後端專案分層
- 介面邏輯涉及資料庫、快取、http請求,如何進行單元測試
- 何為快取穿透、快取擊穿,如何應對他們
應用場景
假如我們正在運營一個線上課程網站,運營人員策劃雙11促銷大降價!於是乎,產品經理鞭策研發對應的活動頁面。我們的開發非常給力,經過數週007力度的勞作,解決無數bug後,活動頁面不負眾望開發完成。我們產品經理開心地把促銷活動頁面連結交給運營人員。運營人員早已準備好活動的簡訊、微博和微信文案模板,就等活動連結下鍋了!但是當看到連結URL時,運營人員陷入了沉思……
https://www.mywebsite.com/courses/promotional-activities/date-1111/ac60ffe3-8ef0-4efa-81d1-edc626569ff0
連結URL比預想的長几倍,加入URL後文案模板給運營人員描繪活動資訊的文字空間所剩無幾。接下來,產品運營、產品經理、技術研發三方,展開長達兩年半年的激烈掰扯。不出意料,出了問題當然還是研發來解決。聰明的研發小夥小明提出瞭解決方案,在Nginx配置一個短的URL跳轉到活動連結URL,問題解決、下班!
運營人員拿到“修改後的”活動連結,得到此次活動的簡訊大致長下面這樣。
當然上面Nginx配置跳轉只是硬編碼方式的一種臨時解決方案,將來有更多類似的活動,維護起來就像是“千層漿糊”,根本無從滿足運營全鏈路深度營銷、矩陣式打法。
魯迅曾經說過:“當軟體設計上遇到問題時,解決方案就是,加一層。” 所以研發組決定開發一個短連結服務,用來維護短URL對映跳轉到長URL。
原理
短連結一般是透過對映關係,將長長的一串網址,對映到幾個字元的短連結上,建立好這種對映關係之後儲存到資料庫裡,使用者每次訪問短連結的時候,需要到資料庫裡查詢這個短連結對應的源網址,然後給使用者跳轉到目標長連結。
短連結從生成到使用分為以下幾步:
- 申請者,請求短連結服務,申請將長連結B生成對應的短連結
- 短連結伺服器生成對應的短連結A,並儲存短連結和長連結的對映關係到資料庫,並返回短連結A給申請者
- 把短連結A拼接到簡訊等的內容上傳送。
- 使用者點選短連結A,瀏覽器用301/302進行重定向,訪問到對應的長連結B。
- 展示對應的內容。
這裡注意http重定向狀態碼301和302的區別:301 永久重定向,302 是臨時重定向。瀏覽器接收到301重定向後會先請求短連結服務,由短連結服務再定向到目標長連結地址,後續瀏覽器再次訪問短連結URL後,便不再經短連結服務跳轉,而是直接訪問目標長連結服務,302的話則每次要經過短連結服務重定向跳轉。(HTTP 中的 301、302、303、307、308 響應狀態碼) 因此,如果要統計訪問量,可以使用302;如果要減少短連結伺服器壓力,可以使用301。
程式碼實踐
魯迅又說: "Talk is cheap, show me the code."
接下來我們用Gin框架實現一個簡單的短連結示例
package main
import (
"fmt"
"log"
"net/http"
"github.com/gin-gonic/gin"
)
// shortLong 短連結ID和目標長連結對映關係,模擬資料庫儲存
var shortLong = map[string]string{
"bd": "https://baike.baidu.com/item/%E7%9F%AD%E9%93%BE%E6%8E%A5/7224556?fr=ge_ala",
"sg": "https://baike.sogou.com/v72514301.htm?fromTitle=%E7%9F%AD%E9%93%BE%E6%8E%A5",
}
// redirectHandler 查詢連結對映,跳轉到目標長連結
func redirectHandler(c *gin.Context) {
shortCode := c.Param("code")
longUrl, ok := shortLong[shortCode]
if !ok {
c.IndentedJSON(http.StatusNotFound, gin.H{
"detail": fmt.Sprintf("短連結(%s)無對應的長連結地址", shortCode),
})
return
}
c.Redirect(http.StatusMovedPermanently, longUrl)
}
func main() {
engine := gin.Default()
engine.GET("/:code", redirectHandler)
if err := engine.Run(":9999"); err != nil {
log.Fatalf("啟動gin server失敗:%v", err)
}
}
程式碼邏輯比較簡單,就不一一解釋了😏。XX,啟動!
[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.
[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
- using env: export GIN_MODE=release
- using code: gin.SetMode(gin.ReleaseMode)
[GIN-debug] GET /:short --> main.redirectHandler (3 handlers)
[GIN-debug] [WARNING] You trusted all proxies, this is NOT safe. We recommend you to set a value.
Please check https://pkg.go.dev/github.com/gin-gonic/gin#readme-don-t-trust-all-proxies for details.
[GIN-debug] Listening and serving HTTP on :9999
在瀏覽器輸入短連結URL:http://127.0.0.1:9999/bd。 我們就能訪問到“長連結”(https://baike.baidu.com/item/%E7%9F%AD%E9%93%BE%E6%8E%A5/7224556?fr=ge_ala)了。
Gin日誌在terminal輸入如下
[GIN] 2024/03/11 - 20:55:22 | 301 | 17.914µs | 127.0.0.1 | GET "/bd"
總結
自此,短連結服務的基本原理和最基本實現就算完成了。下一篇將繼續補充基於Gin實現短連結服務,基礎依賴和架構設計。