前言:某些原因,想直接使用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的错误,不过只有正式线上才有,本地不会有,所以浪费了很多时间),也就是说ServeFile函数第二个参数指向的是你需要反馈的html文件地址
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的资源路径配合
//这里的第二个参数就是你要反馈的资源地址,也就是类似index.html的完整路径
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
,就是这个,使用起来也简单,这里就不多说了
网友评论