看多了 Go 源代碼,看一看應用,尤其是比較短小且有趣的應用代碼,感覺很有意思,而且舉重若輕。
如果順帶修一下小的錯誤,成為 Contributor,那就更多了一種成就感。就像楊文前幾天成為 Go Contributor 那樣,從小處開始,慢慢提升技術含量,總有一天,慢慢成為真正的 Contributor,像曹大那樣。
某天歐神和楊文不知道怎么鼓搗出了一個 golang.design 網站,前一陣子歐神又發布了一個 redir 項目。它其實是一個跳轉,比如,歐神分享的 Gophercon 2020 的 PPT 鏈接:https://golang.design/s/gophercon2020,其實最后會跳轉到一個 dropbox 的一個文件分享頁面。但是用 “/s/gophercon2020” 就會顯得非常的優雅和高級。類似的,還有一些歐神做的分享,如 https://golang.design/s/go2generics 等,都會通過 /s/
跳轉到實際的地址去。至於為什么是 /s/
路徑,其實這個項目最初的名字是 short,也就是短網址的意思。
所以,我今天要介紹的就是 redir 的實現原理以及部署。
首先來看一下 redir 的兩個核心功能:短網址跳轉(/s);處理 go get
請求(/x)。前者很好理解,我訪問短網址 https://golang.design/s/go2generics,redir 給我重定向到真實的 google slice 的地址;后者則不那么好理解,它處理的是我們在項目中 import 了一個 golang.design 下面的某個包,例如:import "golang.design/x/verbose"
,那么 go get
來獲取這個包的時候會去 github 上 golang.design 相應目錄下找,但這一切並不是自然發生的,需要通過返回的 header
告知 go get
一些信息。
對於比較知名的,如 github,我這樣寫:import github.com/go-redis/redis/v8
,go get
就知道去 github 官網去找,但是對於 golang.design 的庫那就不知道怎么找了,所以它會嘗試訪問 https://golang.design/x/pkg/foo?go-get=1
來獲取相關信息,於是 /x
handler 就在 header 里返回 meta 信息,告訴 go get
去 github 找。
當 go get 收到上圖的 HTTP 響應,會根據第一個紅框的提示去 https://github.com/golang-design/verbose 這里找對應的包;而如果是瀏覽器過來的請求,則會重定向到 pkg.go.dev 查看包的詳細信息。前者實際就是和 go get 交互的協議,具體的可以在這里看到。
有了短網址跳轉,自然就想知道訪問每個短網址的 uv/pv 情況,如果訪問路徑 /s
后不接任何字符,那就返回短網址的匯總信息:
了解清楚了功能,我們來看看如何用代碼實現。
main
函數會首先會根據傳入的命令行參數 *daemon 來決定是開啟一個 server,還是執行增加 alias(短鏈接和長鏈接對)、更新 alias 的命令。前者持續運行,后者則只執行一次,程序就會結束。
如果是啟動一個 server,會首先連接 redis,初始化一個本地的 cache,用於加快響應速度;同時會啟動兩個異步協程:counting 和 backup,前者用於計數 uv/pv,后者則用於備份 redis 中的數據。
接着會注冊 /.info
、/s
、/x
三個 handler,/.info
用來看一下程序相關的版本信息(內部會通過 nginx 屏蔽,外部無法訪問);/s
用來處理短鏈接;/x
則用於執行包相關的請求。
/s
的處理邏輯是先從本地 cache 拿和短鏈相對應的實際鏈接,如果沒有拿到,則從 redis 拿,最后調用 http.Redirect(w, r, url, http.StatusTemporaryRedirect)
重定向到實際鏈接地址。
最后,啟動一個異步協程把訪問信息(ip)添加到一個 channel 中去,用於計算 pv/uv。
關於 /s
handler 還有一類特殊的請求,即短鏈接為空,直接訪問 https://golang.design/s/
,那就會返回所有的短鏈接並且展示相應的 uv/pv 信息。
完成上述這些,最后開始監聽端口,處理請求。
另外一個流程就是根據命令行參數執行 alias 的增刪改查,是一次性的行為。
整體的架構圖:
最后我們來看下如何部署到自己的雲主機上,我會修改成自己的域名:qcrao.com。當然,redir 還會向 Google Analytics 發送追蹤數據,需要將 id 改成自己的。
首先要安裝 docker 和 docker-compose,這個就不細說,對着命令敲就好了。
然后編譯 redir.app:
make all
啟動 redir 和 redis 容器:
make up
添加一個新的 alias:
./redir.app -a ck-s -l https://changkun.de/s/
訪問 https://www.qcrao.com/s/,大功告成:
總體來看,項目的邏輯是比較簡單清晰的,但涉及到東西其實也不少,麻雀雖小,五臟俱全。從實現到部署到運維,都需要了解。如果把整個都走通了,還是很有收獲的。
在“玩弄” redir 的過程中,修了一下 Makefile 文件,增加了一個 stats 頁面的排序,也因此成為 redir 的從 Contributor,nice!