基于Knative Serverless技術如何實現(xiàn)一個短網(wǎng)址服務,相信很多沒有經(jīng)驗的人對此束手無策,為此本文總結了問題出現(xiàn)的原因和解決方法,通過這篇文章希望你能解決這個問題。
成都創(chuàng)新互聯(lián)公司堅持“要么做到,要么別承諾”的工作理念,服務領域包括:成都做網(wǎng)站、網(wǎng)站設計、企業(yè)官網(wǎng)、英文網(wǎng)站、手機端網(wǎng)站、網(wǎng)站推廣等服務,滿足客戶于互聯(lián)網(wǎng)時代的松原網(wǎng)站設計、移動媒體設計的需求,幫助企業(yè)找到有效的互聯(lián)網(wǎng)解決方案。努力成為您成熟可靠的網(wǎng)絡建設合作伙伴!
短網(wǎng)址顧名思義就是使用比較短的網(wǎng)址代替很長的網(wǎng)址。維基百科上面的解釋是這樣的:
短網(wǎng)址又稱網(wǎng)址縮短、縮短網(wǎng)址、URL 縮短等,指的是一種互聯(lián)網(wǎng)上的技術與服務,此服務可以提供一個非常短小的 URL 以代替原來的可能較長的URL,將長的 URL 位址縮短。用戶訪問縮短后的 URL 時通常將會重定向到原來的長 URL
雖然現(xiàn)在互聯(lián)網(wǎng)已經(jīng)非常發(fā)達了,但還是有很多場景會對用戶輸入的內容有長度限制。比如 :
微薄、Twitter 長度不能超過 140 個字
一些早期的 BBS 文章單行的長度不能超過 78 字符等場景
運營商短信的長度不能超過 70 個字
而現(xiàn)在很多媒體、電商平臺的內容大多都是多人協(xié)作通過比較復雜的系統(tǒng)、框架生成的,鏈接長度幾十個甚至上百字符都是很平常的事情,所以如果在上述的幾個場景中傳播鏈接使用短網(wǎng)址服務就是一個必然的結果。比如下面這些短信截圖你應該不會陌生:<br />
短網(wǎng)址服務的最初本意就是縮短長 url,方便傳播。但其實短網(wǎng)址服務還能做很多其他的事情。比如下面這些:
訪問次數(shù)的限制,比如只能訪問 1 次,第二次訪問的時候就拒絕服務
時間的限制,比如只能在一周內提供訪問服務,超過一周就拒絕服務
根據(jù)訪問者的地域的限制
通過密碼訪問
訪問量統(tǒng)計
高峰訪問時間統(tǒng)計等等
統(tǒng)計訪問者的一些信息,比如:
來源城市
訪問時間
使用的終端設備、瀏覽器
訪問來源 IP
在營銷活動中其實還可以對不同的渠道生成不通的短網(wǎng)址,這樣通過統(tǒng)計這些短網(wǎng)址還能判斷不同渠道的訪問量等信息
在 Knative 模式下可以實現(xiàn)按需分配,沒有流量的時候實例縮容到零,當有流量進來的時候再自動擴容實例提供服務。<br />現(xiàn)在我們就基于阿里云容器服務的 Knative 來實現(xiàn)一個 serverless 模式的短網(wǎng)址服務。本示例會給出一個完整的 demo,你可以自己在阿里云容器服務上面創(chuàng)建一個 Knative 集群,使用本示例提供服務。本示例中實現(xiàn)一個最簡單的功能
通過接口實現(xiàn)長網(wǎng)址到短網(wǎng)址的映射服務
當用戶通過瀏覽器訪問短網(wǎng)址的時候通過 301 跳轉到長網(wǎng)址
下面我們一步一步實現(xiàn)這個功能
既然要實現(xiàn)短網(wǎng)址到長網(wǎng)址的映射,那么就需要保存長網(wǎng)址的信息到數(shù)據(jù)庫,并且生成一個短的 ID 作為短網(wǎng)址的一部分。所以我們首先需要選型使用什么數(shù)據(jù)庫。在本示例中我們選擇使用阿里云的表格存儲,表格存儲最大的優(yōu)勢就是按量服務,你只需要為你使用的量付費,而且價格也很實惠。如下所示的按量計費價格表。1G 的數(shù)據(jù)保存一年的費用是3.65292元/年( 0.000417 _ 24 _ 365=3.65292) ,是不是很劃算。
我們需要有一個 API 生成短網(wǎng)址
/new?origin-url=${長網(wǎng)址}
origin-url 訪問地址
返回結果
vEzm6v
假設我們服務的域名是 short-url.default.serverless.kuberun.com ,那么現(xiàn)在訪問 http://short-url.default.serverless.kuberun.com/vEzm6v 就可以跳轉到長網(wǎng)址了。
package main import ( "crypto/md5" "encoding/hex" "fmt" "log" "net/http" "os" "strconv" "time" "strings" "github.com/aliyun/aliyun-tablestore-go-sdk/tablestore" ) var ( alphabet = []byte("abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ") l = &Log{} ) func ShortUrl(url string) string { md5Str := getMd5Str(url) var tempVal int64 var result [4]string for i := 0; i < 4; i++ { tempSubStr := md5Str[i*8 : (i+1)*8] hexVal, _ := strconv.ParseInt(tempSubStr, 16, 64) tempVal = 0x3FFFFFFF & hexVal var index int64 tempUri := []byte{} for i := 0; i < 6; i++ { index = 0x0000003D & tempVal tempUri = append(tempUri, alphabet[index]) tempVal = tempVal >> 5 } result[i] = string(tempUri) } return result[0] } func getMd5Str(str string) string { m := md5.New() m.Write([]byte(str)) c := m.Sum(nil) return hex.EncodeToString(c) } type Log struct { } func (log *Log) Infof(format string, a ...interface{}) { log.log("INFO", format, a...) } func (log *Log) Info(msg string) { log.log("INFO", "%s", msg) } func (log *Log) Errorf(format string, a ...interface{}) { log.log("ERROR", format, a...) } func (log *Log) Error(msg string) { log.log("ERROR", "%s", msg) } func (log *Log) Fatalf(format string, a ...interface{}) { log.log("FATAL", format, a...) } func (log *Log) Fatal(msg string) { log.log("FATAL", "%s", msg) } func (log *Log) log(level, format string, a ...interface{}) { var cstSh, _ = time.LoadLocation("Asia/Shanghai") ft := fmt.Sprintf("%s %s %s\n", time.Now().In(cstSh).Format("2006-01-02 15:04:05"), level, format) fmt.Printf(ft, a...) } func handler(w http.ResponseWriter, r *http.Request) { l := &Log{} l.Infof("Hello world received a request, url: %s", r.URL.Path) l.Infof("url:%s ", r.URL) //if r.URL.Path == "/favicon.ico" { // http.NotFound(w, r) // return //} urls := strings.Split(r.URL.Path, "/") originUrl := getOriginUrl(urls[len(urls)-1]) http.Redirect(w, r, originUrl, http.StatusMovedPermanently) } func new(w http.ResponseWriter, r *http.Request) { l.Infof("Hello world received a request, url: %s", r.URL) l.Infof("url:%s ", r.URL) originUrl, ok := r.URL.Query()["origin-url"] if !ok { l.Errorf("no origin-url params found") w.WriteHeader(http.StatusBadRequest) w.Write([]byte("Bad request!")) return } surl := ShortUrl(originUrl[0]) save(surl, originUrl[0]) fmt.Fprint(w, surl) } func getOriginUrl(surl string) string { endpoint := os.Getenv("OTS_TEST_ENDPOINT") tableName := os.Getenv("TABLE_NAME") instanceName := os.Getenv("OTS_TEST_INSTANCENAME") accessKeyId := os.Getenv("OTS_TEST_KEYID") accessKeySecret := os.Getenv("OTS_TEST_SECRET") client := tablestore.NewClient(endpoint, instanceName, accessKeyId, accessKeySecret) getRowRequest := &tablestore.GetRowRequest{} criteria := &tablestore.SingleRowQueryCriteria{} putPk := &tablestore.PrimaryKey{} putPk.AddPrimaryKeyColumn("id", surl) criteria.PrimaryKey = putPk getRowRequest.SingleRowQueryCriteria = criteria getRowRequest.SingleRowQueryCriteria.TableName = tableName getRowRequest.SingleRowQueryCriteria.MaxVersion = 1 getResp, _ := client.GetRow(getRowRequest) colmap := getResp.GetColumnMap() return fmt.Sprintf("%s", colmap.Columns["originUrl"][0].Value) } func save(surl, originUrl string) { endpoint := os.Getenv("OTS_TEST_ENDPOINT") tableName := os.Getenv("TABLE_NAME") instanceName := os.Getenv("OTS_TEST_INSTANCENAME") accessKeyId := os.Getenv("OTS_TEST_KEYID") accessKeySecret := os.Getenv("OTS_TEST_SECRET") client := tablestore.NewClient(endpoint, instanceName, accessKeyId, accessKeySecret) putRowRequest := &tablestore.PutRowRequest{} putRowChange := &tablestore.PutRowChange{} putRowChange.TableName = tableName putPk := &tablestore.PrimaryKey{} putPk.AddPrimaryKeyColumn("id", surl) putRowChange.PrimaryKey = putPk putRowChange.AddColumn("originUrl", originUrl) putRowChange.SetCondition(tablestore.RowExistenceExpectation_IGNORE) putRowRequest.PutRowChange = putRowChange if _, err := client.PutRow(putRowRequest); err != nil { l.Errorf("putrow failed with error: %s", err) } } func main() { http.HandleFunc("/", handler) http.HandleFunc("/new", new) port := os.Getenv("PORT") if port == "" { port = "9090" } if err := http.ListenAndServe(fmt.Sprintf(":%s", port), nil); err != nil { log.Fatalf("ListenAndServe error:%s ", err.Error()) } }
代碼我已經(jīng)編譯成鏡像,你可以直接使用 registry.cn-hangzhou.aliyuncs.com/knative-sample/shorturl:v1 此鏡像編部署服務。
首先到阿里云開通表格存儲服務,然后創(chuàng)建一個實例和表。我們需要的結構比較簡單,只需要短 URL ID 到長 URL 的映射即可,存儲表結構設計如下:
名稱 | 描述 |
---|---|
id | 短網(wǎng)址 ID |
originUrl | 長網(wǎng)址 |
登陸到阿里云以后鼠標浮動在頁面的右上角頭像,然后點擊 accesskeys 跳轉到 accesskeys 管理頁面<br /> <br />點擊顯示即可顯示 Access Key Secret<br />
Knative Service 的配置如下, 使用前兩步的配置信息填充 Knative Service 的環(huán)境變量。然后部署到 Knative集群即可
apiVersion: serving.knative.dev/v1alpha1 kind: Service metadata: name: short-url namespace: default spec: template: metadata: labels: app: short-url annotations: autoscaling.knative.dev/maxScale: "20" autoscaling.knative.dev/minScale: "0" autoscaling.knative.dev/target: "100" spec: containers: - image: registry.cn-hangzhou.aliyuncs.com/knative-sample/shorturl:v1 ports: - name: http1 containerPort: 8080 env: - name: OTS_TEST_ENDPOINT value: http://t.cn-hangzhou.ots.aliyuncs.com - name: TABLE_NAME value: ${TABLE_NAME} - name: OTS_TEST_INSTANCENAME value: ${OTS_TEST_INSTANCENAME} - name: OTS_TEST_KEYID value: ${OTS_TEST_KEYID} - name: OTS_TEST_SECRET value: ${OTS_TEST_SECRET}
使用上面的 knative service 部署服務,部署好以后可能是下面這樣:
└─# kubectl get ksvc short-url http://short-url.default.serverless.kuberun.com short-url-456q9 short-url-456q9 True
現(xiàn)在可以開始測試
生成一個短網(wǎng)址
└─# curl 'http://short-url.default.serverless.kuberun.com/new?origin-url=https://help.aliyun.com/document_detail/121534.html?spm=a2c4g.11186623.6.786.41e074d9oHpbO2' vEzm6v
curl 命令輸出的結果 VR7baa 就是短網(wǎng)址的 ID
訪問短網(wǎng)址<br /> 在瀏覽器中打開 http://short-url.default.serverless.kuberun.com/vEzm6v 就能跳轉到長 url 網(wǎng)址了。
本實戰(zhàn)我們只需三步就基于 Knative 實現(xiàn)了一個 Serverless 的短網(wǎng)址服務,此短網(wǎng)址服務在沒有請求的時候可以縮容到零節(jié)省計算資源,在有很多請求的時候可以自動擴容。并且使用了阿里云表格存儲,這樣數(shù)據(jù)庫也是按需付費?;?Knative + TableStore 實現(xiàn)了短網(wǎng)址服務的 Serverless 化。
看完上述內容,你們掌握基于Knative Serverless技術如何實現(xiàn)一個短網(wǎng)址服務的方法了嗎?如果還想學到更多技能或想了解更多相關內容,歡迎關注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝各位的閱讀!
本文題目:基于KnativeServerless技術如何實現(xiàn)一個短網(wǎng)址服務
鏈接分享:http://bm7419.com/article18/jjesgp.html
成都網(wǎng)站建設公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站營銷、虛擬主機、外貿建站、面包屑導航、定制開發(fā)、域名注冊
聲明:本網(wǎng)站發(fā)布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經(jīng)允許不得轉載,或轉載時需注明來源: 創(chuàng)新互聯(lián)