Golang Header 中的 UTF-8 檔名
一般來說如果你想讓 Golang 去 Serve 一個 File 你會在檔頭加入以下兩行: w.Header().Set("Content-Disposition", "attachment; filename=" + filepath.Base(realFilepath)) w.Header().Set("Content-Type", r.Header.Get("Content-Type")) 這樣瀏覽器就不會播放多媒體檔案而是轉為下載模式。然而,對於一些含有特別字元 / 空格的檔案名稱,一般瀏覽器並無法完整讀取整個檔名,例如: Chōcho - Authentic Symphony (Acoustic ver.).mp4 //檔案名稱下載時因為空格會被 Firefox 讀取成 Chōcho 而如果要解決這個問題,你可以使用 Golang 的 url.QueryEscape( ) 功能,把檔案名稱先轉換為 URL Safe 的名稱,但是這會出現另一個問題,例如上面的例子經過 QueryEscape 之後會變成這樣 Chōcho+-+Authentic+Symphony+(Acoustic+ver.).mp4 這是因為雖然標準裡面有寫到 URL Encode + 跟 " "(空格)是相等的,但是很多主流瀏覽器對 URL Encode 的解讀只有 %20 而已,所以要解決這問題你就只能夠再把 + 替換成 %20 ,完整的代碼如下: w.Header().Set("Content-Disposition", "attachment; filename*=UTF-8''" + strings.ReplaceAll(url.QueryEscape(filepath.Base(realFilepath)),"+","%20")) w.Header().Set("Content-Type", r.Header.Get("Content-Type")) 那你可能會說你的 + 號不就是不見了嗎?嗯,沒錯,可是你有更好的解決方法嗎?
Golang 在 filepath.Glob 裡使用含方括號([ 跟 ])的路徑
由於 Golang 語言限制,filepath.Glob 裡面有一些字元是不能用的,例如說 [ 跟 ] 就是其中之一(還有 * 號,但是大部分作業系統都不會讓你把 * 號當作資料夾名稱,所以在這裡就不作處理了。一般來說,如果你要打開一個包含 [ ] 的路徑, filepath.Glob 會回傳空值。 path := "mymusic[mp3]/*" files, err := filepath.Glob(path); // files 會回傳空值 所以,很多工程師就幹脆不在資料夾名稱裡面使用 [ 跟 ],但是作為開發網頁版的檔案管理器,由於作為工程師是無法預計用戶的使用方式,我們必將要在 Glob 裡面支援 [ 跟 ],而方法可能比你想像中的簡單: realpath := "mymusic[mp3]" files, _ := filepath.Glob(realpath + "*") //這裡的 files 會是空值,寫在這裡是為了在下面省下一個 else 的 case if (strings.Contains(realpath, "[") == true || strings.Contains(realpath, "]") == true){ if (len(files) == 0){ //特別處理模式,以 * 號取代 [ 跟 ] newSearchPath := strings.ReplaceAll(realpath, "[","*") newSearchPath = strings.ReplaceAll(newSearchPath, "]","*") //掃描與輸入路徑相近的路徑名稱 tmpFilelist, _ := filepath.Glob(newSearchPath + "*") //在每個相近路徑中,找出擁有正確路徑的檔案 for _, file := range tmpFilelist{ file = filepath.ToSlash(file) if strings.Contains(file, realpath){ files = append(files, file) } } } } //正確回傳 log.Println(files)
Golang Struct 與 JSON 的快速轉換法
作為前 PHP 開發者,一說到 Golang 要把東西轉做 JSON 就頭痛,因為在 php 裡面你可以非常簡單的把一個複雜的結構轉換成 json,例如說: 就能夠輸出 所以在開發 php 的時候基本上是不用特別處理 json 的轉換的,到了 javascript 一端也能夠輕易的把收回來的資料直接使用,例如: $.get("url_here",function(data){ console.log(data[0]); }); // 輸出 "Hello" 但是去到 Golang 之後寫法就完全不同了,在這篇簡短的文章中,我會簡單介紹一下怎樣輕易的把任何資料 parse 成 JSON string 及由 JSON string 轉回原本型態的方法 Golang 的 Struct 是一樣很神奇的東西 甚麼是 Golang Struct 呢?這個跟 C 語言裡的沒差太遠,簡單來說就是 Golang 上 OOP 的方法。以下是一個簡單的 Struct 例子(原碼取自 ArOZ Online 1.0) type desktopObject struct{ Filepath string; Filename string; Ext string; IsDir bool; IsShortcut bool; IconX int; IconY int; } 把 Struct 轉換成 JSON 這是一個用來定義桌面上的物品的 struct。要把它轉到 JSON 十分簡單,首先你要新建一個 Object thisFileObject := new(desktopObject) 然後把資料填進去,例如這樣 thisFileObject.Filepath = path; thisFileObject.Filename = filepath.Base(path) thisFileObject.Ext = filepath.Ext(path) thisFileObject.IsDir = IsDir(path) 最後把它壓成一個 JSON String jsonString, err:= json.Marshal(desktopFiles); if (err != nil){ //錯誤處理 } return string(jsonString); 就是這樣你的 JSON String 就做好了 由 JSON 轉回 Struct 這個就難一點了,但是還是能做到的。簡單來說就是把 JSON string map 到一個現有的 struct 上面去。先假設我們有以下的一個 struct type iconLocation struct{ X int; Y int; } 和一個 JSON string jsonstring := "你要轉換的東西" 首先你跟上面做的一樣,先預留一個變數給 json unmarshal 時用。然後把 json string 轉換到這個 struct 裡面。 thisLocation := new(iconLocation) json.Unmarshal([]byte(jsonstring ), &thisLocation) fmt.Println(thisLocation) 這樣你就完全把 JSON string 轉回去 struct 了。有夠簡單吧?