一、場景和目標:
用戶上傳一個包含 index.html 的靜態資源壓縮包,資源內所有文件都是相互依賴的,不需要用戶對內部文件內容做任何特殊處理,僅通過服務端邏輯處理達到用戶訪問 http://xxx.xxx/guid/index.html 時就可以得到這個資源的所有數據並正常瀏覽。
二、技術:
nodejs、express
npm 包:decompress、request、crypto、pinyin
三、思路:
a、上傳解析:
對每一個資源生成唯一的 guid,將用戶上傳的壓縮包解壓之后,按照解壓完成的文件的目錄結構以 guid 為初始前綴拼接路徑,這樣就可以保證所有文件在 cdn 的相對路徑就是文件在原始資源包中的相對路徑,然后對文件信息和路徑進行存儲即可。
b、訪問index:
用戶首先要獲得靜態資源的列表,其實就是獲得所有靜態資源的 guid 列表,或者說是靜態資源的唯一 id,這個唯一 id 都會對應一個唯一的 guid,當用戶訪問 [http://xxx.xxx/:id/ | http://xxx.xxx/:id/index | http://xxx.xxx/:id/index.html] 這些路徑時,配置中間件,通過 id 處理中間件去服務端獲取此 id 對應的 guid 值,然后拼接 index 文件的 cdn 地址,pipe 回瀏覽器。
c、獲取相對路徑資源:
當瀏覽器拿到 index 文件之后,index 文件中的所有依賴都會以 index 文件的前置路徑為基准進行獲取,也就是說如果現在依賴一個 index.js 文件,這個文件相對於 index.html 文件的路徑是/scripts/index.js,那么服務端就會收到一個請求,這個請求的 url 是 http://xxx.xxx/:id/scripts/index.js,這里為了保證請求的正確性,並沒有在 index 文件 guid 解析完成之后向 cookie 中存儲 guid,而是所有靜態資源的請求都去獲取新的 guid 值,拿到 guid 之后,就可以通過相對路徑拼合出此靜態文件在 cdn 中存儲的位置路徑信息,路徑信息拼合好之后,使用 request 包的 pipe 方法直接相應給用戶 cdn 中靜態資源的數據即可。
通過上面三個步驟,就可以實現上面場景中所描述的要求,是此類問題的一種處理方式。
四、遇到的問題:
a、數據存儲
由於項目是以靜態資源為主的,因此要求服務端部分要輕量,因此在服務端處理邏輯中未加入任何數據庫、公有配置、權限、登陸等功能,所有的數據交互全部通過主項目的對外接口進行接入,保證了項目中服務端部分只有純邏輯,代碼量也比較少,是一種不錯的選擇。
b、確定所有目標文件位置
在這里遇到一個問題就是,如果用戶上傳的壓縮包中存在一些不合法的或者不需要使用的額外文件怎么辦,理論來說在服務端無法確定哪些文件是需要被引用的,但是根據上傳規定和要求,資源包內最外層一定要有一個 index.html 文件,那么就可以通過 index 文件進行處理,只保留和 index 同層及其下層的文件,這樣可以保證 index 文件一定是在最外層的,其余文件全部忽略,保證只存儲有用的資源。
c、三方npm包解壓壓縮包時中文問題
剛開始使用的一個 npm 包解壓之后中文是亂碼,上傳 cdn 后找不到此文件,后面對亂碼文件的路徑進行 encode,然后可以在 cdn找到此文件了,但是再向用戶 pipe 時出現問題,被 encode 的文件無法 pipe,雖然文件請求返回了200,但是資源數據就是拿不到,很惆悵,在嘗試了五六個包之后,終於找到一個可以對中文進行正常解壓的包,算是先解決了亂碼問題,可encode 后無法向用戶 pipe 的問題還是沒有解決,於是想到了下面的方式。
d、阿里雲cdn向用戶pipe文件時被encode的文件回傳失敗
由於 encode 的文件回傳失敗,直接存儲中文也不是很好,因此想到將中文轉換為拼音的辦法,就是在讀取資源包中的文件並拼合其 cdn 路徑時,對路徑中的中文進行轉換,轉為拼音,然后用戶訪問這些文件時對訪問的 url 也進行拼音轉換,這樣就確保了數據的正確性同時也避免在數據庫和 cdn 中存儲中文導致的各種問題。
五、流程圖:
六、示例:
假設現在上傳了個資源包,解壓后目錄結構長下面這個樣子:
/yyy /zzz zzz.html /xxx index.html /js index.js /css index.css /images index.png
生成的 guid 長后面這個樣子:abcdefghijklmnopqrstuvwzyx。
那么這些資源的 cdn 地址就是下面的樣子:
/abcdefghijklmnopqrstuvwzyx/index.html /abcdefghijklmnopqrstuvwzyx/js/index.js /abcdefghijklmnopqrstuvwzyx/css/index.css /abcdefghijklmnopqrstuvwzyx/images/index.png
在 views 中將會存在一個名為abcdefghijklmnopqrstuvwzyx的文件夾,里面靜靜的躺着 index.html 文件等待被用戶訪問。
七、結束。