前言:某些原因,想直接使用go編譯生成的可執行文件+前端編譯好的靜態文件,直接佈置項目,不用依賴於nginx。

想看結果的同學直接拉到最下面看代碼和總結

開始探索:

首先想到的是golang路由中指向靜態資源

知識點:http中的ServeFile方法和FileServe,這兩個很像,這裏使用第一個,區分自己去查,這個一般

只需要在你的HandlerFunc中指向你的資源地址,就可以反饋,這裏本地使用了一個測試html,結果沒問題

http.ServeFile(w, r, "./test.html")

你以爲成功了,不不不,實際佈置後馬上給你出問題了

正式環境是這樣的,因爲靜態資源放在同一級目錄

http.ServeFile(w, r, "./dist/index.html")

問題發現(出現新問題):

訪問地址,啥也沒有~~~,檢查問題,發現

image.png

這兩句話:

Resource interpreted as Stylesheet but transferred with MIME type text/plain: 
"http://localhost:5001/css/app.5e843a4a.css".
localhost/:1 Resource interpreted as Stylesheet but transferred with MIME type text/plain: 
"http://localhost:5001/css/chunk-vendors.43fc3011.css".

他說的大概意思是這個css解析的不對,直接變成文本傳輸的了,然後就發現mime這個是啥呢,查了一下資料,叫“多用途互聯網郵件擴展類型”,就是文件類型解析的時候對應哪一個類型來解析,比如說這裏,“.css”文件應該用“text/css”來解析,但是他用錯了,所以變成了文本。

繼續查資料。

看到了一句話,說是加一句

w.Header().Add("Content-Type", "text/plain")

這樣不對,反饋的直接變成文本了,雖然錯誤沒了,但是我要的是html顯示啊~~~~,排除

image.png

問題發現,與mime相關(出現新問題)

終於,找到了原因,查閱相關資料得出,nginx有自己的mime文件,所以不會有問題,

使用go的程序執行時,調用的是系統的mime文件,可能會出現問題。

找到問題了,當然就知道怎麼做了,直接搜索,golang mime,看看有沒有解決辦法,還真的有這個包“mime”,內容也簡單,就幾個函數,具體的就不說了,就說這裏用到的。

func init() {
    mime.AddExtensionType(".js", "text/javascript")
    mime.AddExtensionType(".css", "text/css; charset=utf-8")
}

在init中增加這個方法,意思是,告訴他,這個類型的文件,用後面這種方式去解析,別搞錯了,他就知道了。繼續測試,看看是否成功呢!

果然不出所料,還是不行(如果是線上服務器環境,這裏可能會有404資源錯誤)~~~

image.png

問題解決(方法正確):

爲什麼呢,想不通~~~,繼續查資料,擦查了好久都沒有發現問題,突然,看到了這個路由,聯想到剛剛出現的404,突然想到,方法是對了,可能資源路徑不對吧。

http://localhost:3000/css/chunk-vendors.43fc3011.css

就像上面出現的這個路徑,他肯定不對啊,肯定沒有這個資源啊,懷着試一試的態度,調整一下自己的路由,加上下面這個代碼

if paths[0] == "css" || paths[0] == "js" || paths[0] == "fonts" {
        str, err := os.Getwd()
        if err != nil {
            logrus.WithFields(logrus.Fields{"path": err.Error()}).Warn("getwd")
            return
        }
        http.ServeFile(w, r, filepath.Join(str, "dist", paths[0], paths[len(paths)-1]))
        return
    }

測試了一下,居然成功了,哇哇哇哇,哈哈哈哈哈

image.png

最後總結一下:

1.完整資源佈置需要的幾步

1.1.需要自己調節url的資源訪問路徑,並將它們用ServeFile指向你的index.html,css,js等資源(這一步很難想到,中間可能會有404的錯誤,不過只有正式線上纔有,本地不會有,所以浪費了很多時間)

1.2.使用mime包,使得go程序可以正確解析靜態資源文件類型

2.測試總代碼(我這裏vue生成的dist文件夾放在可執行文件同一級,你們需要注意自己的路徑):

package main

import (
    "mime"
    "net/http"
    "net/url"
    "os"
    "path/filepath"
    "strings"

    "github.com/Sirupsen/logrus"
)

func init() {
    mime.AddExtensionType(".js", "text/javascript")
    mime.AddExtensionType(".css", "text/css; charset=utf-8")
}

func main() {
    http.Handle("/", http.HandlerFunc(httpProcess))
    http.ListenAndServe(":5001", nil)
}

func httpProcess(w http.ResponseWriter, r *http.Request) {
    if r.URL.String() == "/" {
        str, err := os.Getwd()
        if err != nil {
            logrus.WithFields(logrus.Fields{"path": err.Error()}).Warn("getwd")
            return
        }
        http.ServeFile(w, r, filepath.Join(str, "dist", "index.html")) //反饋靜態主頁,需要下面css,和js以及fonts的資源路徑配合
        return
    }
    paths, err := parsePaths(r.URL)
    //這裏的path反饋工作元素內容待定
    if err != nil {
        logrus.Error(err)
        w.WriteHeader(http.StatusBadRequest)
        w.Write(nil)
        return
    }

    if paths[0] == "css" || paths[0] == "js" || paths[0] == "fonts" {
        str, err := os.Getwd()
        if err != nil {
            logrus.WithFields(logrus.Fields{"path": err.Error()}).Warn("getwd")
            return
        }
        http.ServeFile(w, r, filepath.Join(str, "dist", paths[0], paths[len(paths)-1]))
        return
    }
}
//解析url
func parsePaths(u *url.URL) ([]string, error) {
    paths := []string{}
    pstr := u.EscapedPath()
    for _, str := range strings.Split(pstr, "/")[1:] {
        s, err := url.PathUnescape(str)
        if err != nil {
            return nil, err
        }
        paths = append(paths, s)
    }
    return paths, nil
}
l

附錄:還可以使用一個縮小包,來減少靜態資源中的大小 github.com/tdewolff/minify ,就是這個,使用起來也簡單,這裏就不多說了

歡迎關注我們的微信公衆號,每天學習Go知識

相關文章