前言:某些原因,想直接使用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知识

相关文章