使用Go語(yǔ)言開(kāi)發(fā)短鏈接服務(wù)的方法
源碼:https://gitee.com/alxps/short_link
通過(guò)這個(gè)項(xiàng)目,你可以學(xué)到:
- 短鏈接原理
- Golang后端項(xiàng)目分層
- 接口邏輯涉及數(shù)據(jù)庫(kù)、緩存、http請(qǐng)求,如何進(jìn)行單元測(cè)試
- 何為緩存穿透、緩存擊穿,如何應(yīng)對(duì)他們
應(yīng)用場(chǎng)景
假如我們正在運(yùn)營(yíng)一個(gè)在線課程網(wǎng)站,運(yùn)營(yíng)人員策劃雙11促銷大降價(jià)!于是乎,產(chǎn)品經(jīng)理鞭策研發(fā)對(duì)應(yīng)的活動(dòng)頁(yè)面。我們的開(kāi)發(fā)非常給力,經(jīng)過(guò)數(shù)周007力度的勞作,解決無(wú)數(shù)bug后,活動(dòng)頁(yè)面不負(fù)眾望開(kāi)發(fā)完成。我們產(chǎn)品經(jīng)理開(kāi)心地把促銷活動(dòng)頁(yè)面鏈接交給運(yùn)營(yíng)人員。運(yùn)營(yíng)人員早已準(zhǔn)備好活動(dòng)的短信、微博和微信文案模板,就等活動(dòng)鏈接下鍋了!但是當(dāng)看到鏈接URL時(shí),運(yùn)營(yíng)人員陷入了沉思……
鏈接URL比預(yù)想的長(zhǎng)幾倍,加入U(xiǎn)RL后文案模板給運(yùn)營(yíng)人員描繪活動(dòng)信息的文字空間所剩無(wú)幾。接下來(lái),產(chǎn)品運(yùn)營(yíng)、產(chǎn)品經(jīng)理、技術(shù)研發(fā)三方,展開(kāi)長(zhǎng)達(dá)兩年半年的激烈掰扯。不出意料,出了問(wèn)題當(dāng)然還是研發(fā)來(lái)解決。聰明的研發(fā)小伙小明提出了解決方案,在Nginx配置一個(gè)短的URL跳轉(zhuǎn)到活動(dòng)鏈接URL,問(wèn)題解決、下班!
運(yùn)營(yíng)人員拿到“修改后的”活動(dòng)鏈接,得到此次活動(dòng)的短信大致長(zhǎng)下面這樣。
當(dāng)然上面Nginx配置跳轉(zhuǎn)只是硬編碼方式的一種臨時(shí)解決方案,將來(lái)有更多類似的活動(dòng),維護(hù)起來(lái)就像是“千層漿糊”,根本無(wú)從滿足運(yùn)營(yíng)全鏈路深度營(yíng)銷、矩陣式打法。
魯迅曾經(jīng)說(shuō)過(guò):“當(dāng)軟件設(shè)計(jì)上遇到問(wèn)題時(shí),解決方案就是,加一層。” 所以研發(fā)組決定開(kāi)發(fā)一個(gè)短鏈接服務(wù),用來(lái)維護(hù)短URL映射跳轉(zhuǎn)到長(zhǎng)URL。
原理
短鏈接一般是通過(guò)映射關(guān)系,將長(zhǎng)長(zhǎng)的一串網(wǎng)址,映射到幾個(gè)字符的短鏈接上,建立好這種映射關(guān)系之后保存到數(shù)據(jù)庫(kù)里,用戶每次訪問(wèn)短鏈接的時(shí)候,需要到數(shù)據(jù)庫(kù)里查詢這個(gè)短鏈接對(duì)應(yīng)的源網(wǎng)址,然后給用戶跳轉(zhuǎn)到目標(biāo)長(zhǎng)鏈接。
短鏈接從生成到使用分為以下幾步:
- 申請(qǐng)者,請(qǐng)求短鏈接服務(wù),申請(qǐng)將長(zhǎng)鏈接B生成對(duì)應(yīng)的短鏈接
- 短鏈接服務(wù)器生成對(duì)應(yīng)的短鏈接A,并保存短鏈接和長(zhǎng)鏈接的映射關(guān)系到數(shù)據(jù)庫(kù),并返回短鏈接A給申請(qǐng)者
- 把短鏈接A拼接到短信等的內(nèi)容上發(fā)送。
- 用戶點(diǎn)擊短鏈接A,瀏覽器用301/302進(jìn)行重定向,訪問(wèn)到對(duì)應(yīng)的長(zhǎng)鏈接B。
- 展示對(duì)應(yīng)的內(nèi)容。
這里注意http重定向狀態(tài)碼301和302的區(qū)別:301 永久重定向,302 是臨時(shí)重定向。瀏覽器接收到301重定向后會(huì)先請(qǐng)求短鏈接服務(wù),由短鏈接服務(wù)再定向到目標(biāo)長(zhǎng)鏈接地址,后續(xù)瀏覽器再次訪問(wèn)短鏈接URL后,便不再經(jīng)短鏈接服務(wù)跳轉(zhuǎn),而是直接訪問(wèn)目標(biāo)長(zhǎng)鏈接服務(wù),302的話則每次要經(jīng)過(guò)短鏈接服務(wù)重定向跳轉(zhuǎn)。(HTTP 中的 301、302、303、307、308 響應(yīng)狀態(tài)碼) 因此,如果要統(tǒng)計(jì)訪問(wèn)量,可以使用302;如果要減少短鏈接服務(wù)器壓力,可以使用301。
代碼實(shí)踐
魯迅又說(shuō): "Talk is cheap, show me the code."
接下來(lái)我們用Gin框架實(shí)現(xiàn)一個(gè)簡(jiǎn)單的短鏈接示例
package main import ( "fmt" "log" "net/http" "github.com/gin-gonic/gin" ) // shortLong 短鏈接ID和目標(biāo)長(zhǎng)鏈接映射關(guān)系,模擬數(shù)據(jù)庫(kù)存儲(chǔ) 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 查找鏈接映射,跳轉(zhuǎn)到目標(biāo)長(zhǎng)鏈接 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)無(wú)對(duì)應(yīng)的長(zhǎng)鏈接地址", 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("啟動(dòng)gin server失敗:%v", err) } }
代碼邏輯比較簡(jiǎn)單,就不一一解釋了??。XX,啟動(dòng)!
[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。 我們就能訪問(wèn)到“長(zhǎng)鏈接”(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"
總結(jié)
自此,短鏈接服務(wù)的基本原理和最基本實(shí)現(xiàn)就算完成了
到此這篇關(guān)于使用Go語(yǔ)言開(kāi)發(fā)一個(gè)短鏈接服務(wù)的文章就介紹到這了,更多相關(guān)Go語(yǔ)言短鏈接服務(wù)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
執(zhí)行g(shù)o?vendor第三方包版本沖突問(wèn)題解決
這篇文章主要為大家介紹了執(zhí)行g(shù)o?vendor時(shí),第三方包go版本沖突問(wèn)題的解決方法,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-07-07如何使用go-zero開(kāi)發(fā)線上項(xiàng)目
這篇文章主要介紹了如何使用go-zero開(kāi)發(fā)線上項(xiàng)目,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-12-12淺析golang?github.com/spf13/cast?庫(kù)識(shí)別不了自定義數(shù)據(jù)類型
這篇文章主要介紹了golang?github.com/spf13/cast庫(kù)識(shí)別不了自定義數(shù)據(jù)類型,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-08-08Goland激活碼破解永久版及安裝詳細(xì)教程(親測(cè)可以)
這篇文章主要介紹了Goland激活碼破解永久版及安裝詳細(xì)教程(親測(cè)可以),本文通過(guò)實(shí)例圖文相結(jié)合給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-10-10go?install和go?get的區(qū)別實(shí)例詳解
go install是Golang用來(lái)編譯和安裝自定義package的工具,下面這篇文章主要給大家介紹了關(guān)于go?install和go?get區(qū)別的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-01-01