聊聊短地址及其原理

NO IMAGE

簡介

一個同事遇到一個問題,他說受限於第三方的服務,自己請求所帶過去的字符串因為太長,無法從第三方服務獲取信息,很是苦惱😴。後來我們商量了一下,最終借鑑短地址的思想解決了問題。道理很簡單,因為我們請求中的附加字符串信息第三方服務只是透傳回來給我們,我們只需要把這些附加信息進行字符壓縮就可以了,這樣請求帶過去的字符串長度就滿足了要求😊。

無論是寫文章還是製作一些表格的時候,我會時常用到短地址。短地址的優勢在於其短(字符少)、簡潔,方便書寫又不佔位置。方便在社交網絡和第三方平臺上分享鏈接,投放廣告。比如有人會在發朋友圈的時候帶上短地址,還有一些營銷短信裡面也會帶一些短地址鏈接。

有現成的短地址生成器,常用的短地址轉換有 百度短網址轉換Google短網址轉換新浪短地址轉換,可惜的是谷歌關閉了該服務,官方發言如下:

On March 30, 2018, we turned down support for goo.gl URL shortener. 
From April 13, 2018, only existing users were able to create short links on the goo.gl console.
Analytics data was available for up to one year, until March 30, 2019, when goo.gl was discontinued. 
Previously created links will continue to redirect to their intended destination. 
Please see this blog post for more details.

我經常使用百度的短地址服務,訪問它是最快的也能滿足我的工作和學習需求,它也提供 API 服務可以參考 短網址生成接口文檔 學習和了解。

我們先來了解一下 HTTP 協議中那些重定向的事。

HTTP 請求重定向

HTTP 中的 301302303307308 響應狀態碼,都表示重定向的響應。

其中,301308 響應狀態碼錶示永久重定向,302303307 表示臨時重定向。

那我們來說一下什麼是重定向?

重定向(Redirect)就是通過各種方法將各種網絡請求重新定個方向轉到其它位置(如:網頁重定向、域名的重定向、路由選擇的變化也是對數據報文經由路徑的一種重定向)。

舉個例子,你要去 A 部門辦理一個證件,等你去了之後A部門的某人告訴你他們不再受理此事了,需要你去 B 部門辦理,然後你就自己去了 B 部門。這個過程就類似於重定向。

那麼,HTTP 協議中定義的這些30X響應狀態碼就好比 A部門的某人 它們告訴客戶端,你需要訪問另外一個地址了。

重定向做了兩次 HTTP 請求, 第一次,客戶端請求 A 服務器,A 響應告訴瀏覽器,你應該去 B 服務器訪問。此時就去訪問服務器 B,這個時候你可以看到瀏覽器中的網址變了,這就是第二次 HTTP 請求。

重定向過程:

Step-1、瀏覽器(客戶端)發送 HTTP 請求;

Step-2、Web服務器A接收後發送 302 狀態碼響應,並在響應頭中把對應的 Location 給瀏覽器;

Step-3、瀏覽器收到服務器返回的 302 響應碼,就自動再發送一個新的 HTTP 請求(請求URL是新的 Location 中的地址);

Step-4、Web服務器(可能是 A 也可能是其他服務器)根據此請求尋找資源併發送給瀏覽器,最終展示給用戶。

關於 Location 可以看下面的截圖(這是一個重定向的 HTTP 請求示例),它是被放在響應頭中的,其值是需要重定向的網址 http://www.veryitman.com,從這個過程來看可以看出重定向是客戶端(瀏覽器)行為。

聊聊短地址及其原理

還有個叫轉發的技術,這個和重定向是不一樣的,轉發是服務器行為,還拿上面的 A 部門例子來說,你要去 A 部門辦理一個證件,等你去了之後 A 部門的某人告訴你他們不再受理此事了,但是 A 部門可以自己協調資源幫你完成而不需要你去其他部門辦理了。這個過程就類似於轉發。

模擬重定向

現在使用 SpringBoot 模擬一下重定向,我用的 SpringBoot 是 2.2.0.RELEASE 版本。

①、 新建 SpringBoot Web 工程,可以參考 微服務-想辦法讓項目運行起來 這篇文章。

②、 修改 pom 文件,增加 fastjson,示例如下:

<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.62</version>
</dependency>

③、 新建 MSTestRedirectController 文件,源碼如下:

import com.alibaba.fastjson.JSON;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
@Controller
@RequestMapping(value = "testredirect")
public class MSTestRedirectController {
@GetMapping(value = "/access/web")
public String redirect() {
return "redirect:/testredirect/index/realweb?parameter=coming";
}
@ResponseBody
@GetMapping(value = "/index/realweb")
public String real(HttpServletRequest request) {
return "redirect happened:" + JSON.toJSONString(request.getParameterMap());
}
}

這裡要注意幾個問題:

  • 既然是重定向,該 Controller 不能使用 @RestController 註解而要使用 @Controller 註解;

  • 這裡使用了關鍵字 redirect 實現重定向;

④、 啟動工程,並在瀏覽器訪問下面的網址

http://localhost:8080/testredirect/access/web

可以看到瀏覽器發生了重定向,截圖如下:

聊聊短地址及其原理

除了上面的方法可以實現重定向外還可使用 HttpServletResponsesendRedirect 方法,示例如下:

@GetMapping(value = "/access/web2")
public String redirect2(HttpServletResponse response) {
try {
// 方法1:自定義狀態碼方式
// String url = "http://localhost:8080/testredirect/index/realweb?parameter=coming";
//response.setHeader("Location", url);
//response.sendError(301);
// 方法2:sendRedirect,默認返回的狀態碼是 302
response.sendRedirect("/testredirect/index/realweb?parameter=coming");
} catch (IOException e) {
e.printStackTrace();
} finally {
return "";
}
}

請求短地址過程

我拿網址 http://www.veryitman.com/ 來舉實例,使用百度短地址服務。

百度短地址頁面 去生成 http://www.veryitman.com/ 對應的短地址,如下圖所示:

聊聊短地址及其原理

得到短地址是 https://dwz.cn/hnmau4Zs 複製該地址拷貝到瀏覽器(我用的是 Chrome 瀏覽器)的地址欄中,並打開 Chrome 的審查視圖。切換到 Network 選項,此時回車打開短網址。

聊聊短地址及其原理

HTTP 發送了 GET 請求(紅色1),請求地址是 https://dwz.cn/hnmau4Zs ,服務器(百度的短地址服務)返回給 Chrome 瀏覽器 302 狀態碼,瀏覽器發現是該重定向碼就再次用 Location 裡面包含的地址發送了第二次請求即重定向請求。

你也可以使用微博的短地址服務,提醒一點,微博的短地址請求返回碼是 301 而百度返回的是 302 響應碼。302 狀態碼允許各種各樣的重定向,一般情況下都會實現為到 GET 的重定向,但是不能確保 POST 會重定向為 POST,302 表示舊地址A的資源還在(仍然可以訪問),這個重定向只是臨時地從舊地址A跳轉到地址B;而 301 狀態碼錶明目標資源被永久的移動到了一個新的 URI,任何未來對這個資源的引用都應該使用新的 URI。

短地址原理

剛開始我很好奇,為什麼我把長地址 A 轉換為短地址 B,然後用 B 去訪問居然還是 A 地址的內容,瀏覽器是怎麼做到的?

通過上面的請求過程示例,相信大家應該大概理解了請求短地址的原理了。

在百度短地址服務中,我們將 http://www.veryitman.com/ 轉換為 https://dwz.cn/hnmau4Zs ,此時百度短地址服務維持了 短-長 地址的映射關係了而且是唯一的,當我們去訪問 https://dwz.cn/hnmau4Zs ,其實請求的是百度短地址服務,該服務將短地址對應的長地址(放在響應頭的 Location 中)返回給我們的瀏覽器,並返回 302 狀態碼,此時瀏覽器就重定向到了 http://www.veryitman.com/ 這個網址上了。

簡單總結一下其步驟如下:

Step-1、用戶在瀏覽器裡輸入 https://dwz.cn/hnmau4Zs 這個網址去訪問;

Step-2、瀏覽器解析 DNS,獲取該域名對應的 IP 地址;

Step-3、獲取到 IP 後,瀏覽器發送 HTTP GET 請求查詢 hnmau4Zs 並獲取到 https://dwz.cn/hnmau4Zs 對應的長地址;

Step-4、HTTP 通過 302 狀態碼轉到去請求對應的長地址 http://www.veryitman.com/ 上面了。

我把 http://www.veryitman.com/ 放到百度和微博的短地址生成分別是:

// 百度短地址
https://dwz.cn/hnmau4Zs
// 微博段地址
http://1t.click/aMtD

可以看出百度生成較複雜,首先協議變成了 HTTPS,其次生成代碼是 8 位(hnmau4Zs),而微博生成的是 4 位(aMtD)代碼。

短地址碼一般都是由26個大寫字母 A-Z 、26個小寫字母 a-z 和10個數字 0-9 共62個字符隨機組合而成,那麼可以這樣來生成短地址碼,我們定義一個62進制,把這62個字符按照10進制數轉成62進制數,那麼就可以得到每個字符對應的62進制數了。同理,將短地址還原的時候把62進制轉換為對應的10進制就可以了。

根據上面算法,可以看出百度可以支持 62^8 個短地址,微博可以支持 62^4 個短地址。

關於短地址生成的算法,大家可以用 SpringBoot 自己擼一個或者去網上找找別人已經實現的。


活著不是靠淚水搏取同情,而是靠汗水獲得掌聲~

聊聊短地址及其原理

相關文章

Nginx的這些妙用,你肯定有不知道的!

[解鎖新姿勢]回想起被`ifelse`支配的恐懼,我們要打倒ifelse

全國到底有多少人在看直播?我用Node寫了個爬蟲統計了一下

左邊敲打IDE!右邊出現了一個世界!!!