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

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

下面先演示一下:

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

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

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

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

package main

import (
	"net/http"
	"project02/routers"
)

func main() {

	http.Handle("/assets/", http.StripPrefix("/assets/", http.FileServer(http.Dir("public"))))

	http.Handle("/", routers.StaticFileServe())

	http.ListenAndServe(":6166", nil)
}

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

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

Clean("a/c") = "a/c"
Clean("a//c") = "a/c"
Clean("a/c/.") = "a/c"
Clean("a/c/b/..") = "a/c"
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 将文件内容返回给客户端。

var docRoot = "dist"

func StaticFileServe() (fs http.Handler) {
	docRoot = path.Clean(docRoot)
	_, err := os.Stat(docRoot)
	if err != nil {
		fmt.Println(fmt.Sprintf("配置项docRoot:%s不存在或无权限,请修正", docRoot))
		os.Exit(-1)
		return
	}

	idxFile := docRoot + "/index.html"
	_, err = os.Stat(idxFile)
	if os.IsNotExist(err) {
		fmt.Println(fmt.Sprintf("配置项docRoot:%s不存在,请修正", idxFile))
		os.Exit(-1)
		return
	}

	rootFS := http.FileServer(http.Dir(docRoot))
	fs = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if w == nil || r == nil {
			fmt.Println("w or r is nil", idxFile)
			os.Exit(-1)
			return
		}
		rPath := r.URL.Path
		if !strings.HasPrefix(rPath, "/") {
			rPath = "/" + rPath
			r.URL.Path = rPath
		}

		dstFileName := path.Clean(docRoot + rPath)
		_, err = os.Stat(dstFileName)
		if os.IsNotExist(err) {
            //重定向至首页
			r.URL.Path = "/index.html"
		}

		rootFS.ServeHTTP(w, r)
	})
	return fs
}

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

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

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

 

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

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

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

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

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

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

本次使用版本:

Golang1.17

Vue3+Vite构建工具

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值