分享

不用Nginx,Golang如何部署Vue应用呢?

 F2967527 2024-05-14 发布于北京

这个问题已经困扰了我将近一年了,去年刚开始学习golang的时候,就想过能不能通过golang的静态资源服务器来部署vue打包后的资源呢?这样我就可以一个端口部署前后端分离的应用了,而且还能完美解决跨域问题。但试了好几次,发现只是单页面的应用,这里指的是不带路由的vue应用,是可以直接显示出来的,跟普通的html文件是一样的,但使用了路由之后,打开index.html之后就会显示空白页面。

下面先演示一下:

我们只需要关注dist目录和public目录,dist目录是vue打包后的产物,它的子目录static下存放的是一系列的js和css文件,而public目录就是我们后端的一个静态资源目录,其实两个都是静态资源目录,只不过这里我把两个目录分开,后面起两个静态资源服务器,更好区分。

下面来分析代码,下面这段代码很简单,创建了两个静态资源服务器:

一个是路径前缀为“/assets/”的资源服务器,用于获取public目录下的文件(例如图片,文档等等);另一个是直接为根路径的静态资源服务器,便是这次的重点,用于部署vue打包后的资源的。

(这里需要注意的就是,我刻意用了"/assets/"这个路径而不用"/static/"是为了与dist目录下的static进行一个区分,不然容易发生冲突)

  1. package main
  2. import (
  3. "net/http"
  4. "project02/routers"
  5. )
  6. func main() {
  7. http.Handle("/assets/", http.StripPrefix("/assets/", http.FileServer(http.Dir("public"))))
  8. http.Handle("/", routers.StaticFileServe())
  9. http.ListenAndServe(":6166", nil)
  10. }

 接下来我们来看看StaticFileServe里面做了什么,下面这段代码做的事情也很简单:

前面的path.Clean()的功能就是把传进去的路径变得干净一点,例如:

  1. Clean("a/c") = "a/c"
  2. Clean("a//c") = "a/c"
  3. Clean("a/c/.") = "a/c"
  4. Clean("a/c/b/..") = "a/c"
  5. Clean("/../a/c") = "/a/c"

接下来的两个判断都是判断文件是否存在,rootFS就是以docRoot(dist目录)为静态资源目录的文件服务器,下面的http处理方法中:

使用 strings.HasPrefix 函数检查请求路径是否以 / 开头,如果不是,则将其加上 /。然后,我们使用 path.Clean 函数结合目录根路径 docRoot 和请求路径 rPath,生成最终文件的完整路径 dstFileName

之后,我们使用 os.Stat 函数检查文件是否存在,如果不存在,则将请求路径修改为 /index.html,并重新设置到 r.URL.Path 中。最后,我们调用 rootFS.ServeHTTP 方法,使用 http.ResponseWriter 将文件内容返回给客户端。

  1. var docRoot = "dist"
  2. func StaticFileServe() (fs http.Handler) {
  3. docRoot = path.Clean(docRoot)
  4. _, err := os.Stat(docRoot)
  5. if err != nil {
  6. fmt.Println(fmt.Sprintf("配置项docRoot:%s不存在或无权限,请修正", docRoot))
  7. os.Exit(-1)
  8. return
  9. }
  10. idxFile := docRoot + "/index.html"
  11. _, err = os.Stat(idxFile)
  12. if os.IsNotExist(err) {
  13. fmt.Println(fmt.Sprintf("配置项docRoot:%s不存在,请修正", idxFile))
  14. os.Exit(-1)
  15. return
  16. }
  17. rootFS := http.FileServer(http.Dir(docRoot))
  18. fs = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  19. if w == nil || r == nil {
  20. fmt.Println("w or r is nil", idxFile)
  21. os.Exit(-1)
  22. return
  23. }
  24. rPath := r.URL.Path
  25. if !strings.HasPrefix(rPath, "/") {
  26. rPath = "/" + rPath
  27. r.URL.Path = rPath
  28. }
  29. dstFileName := path.Clean(docRoot + rPath)
  30. _, err = os.Stat(dstFileName)
  31. if os.IsNotExist(err) {
  32. //重定向至首页
  33. r.URL.Path = "/index.html"
  34. }
  35. rootFS.ServeHTTP(w, r)
  36. })
  37. return fs
  38. }

此时基本的部署已经完成,很完美!!但当我打开首页的时候,能不能被显示出来呢?

很遗憾,还是空白页面,那么问题到底出在了哪里?

我打开了浏览器的控制台检查了一番,发现报错了,这个错误提示是因为浏览器在加载 Javascript 模块时,判断服务器返回的 MIME 类型不是 application/javascript 时,就会报出这个错误。

 

那么我是不是只要将响应头的Content-Type的类型改为正确的类型是不是就可以解决这个问题了呢?不哔哔,我们再修改一下代码:

 只需要在刚才的StaticFileServe中添加一段代码:

  1. //对js文件的Content-Type设置正确的类型
  2. if strings.HasSuffix(dstFileName, ".js") {
  3. w.Header().Set("Content-Type", "application/javascript")
  4. }

我们再来看看添加了这段代码后,能不能正常显示页面 

芜湖,完美解决啦,同时vue也能正常处理路由,可以看到我这里直接调整到了login页面上了,同时这时候的类型也修改为了正常的MIME类型了,证明之前确实是因为这个问题导致显示空白页面的。 

在网上摸索了挺久的,也使用过gin,但gin的静态文件资源服务器好像有点问题,我同样修改了响应头的Content-Type但最后获取到的类型依然还是text/plain,具体原因不大清除,希望有知道的小伙伴可以评论区告知一下!!

本次使用版本:

Golang1.17

Vue3+Vite构建工具

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多