本篇博客分两种情况来解决golang项目访问静态资源404问题,第一种是自己将静态页面手动创建或者复制到golang项目中。第二种情况是采用第三方框架vue-elementui-template打包生成的文件静态资源404问题

简单项目的静态资源404问题

问题
在这里插入图片描述

运行golang项目后,打开index.html页面后各种js、css加载404问题。不多比比,直接上代码。

test1.go

package main

import (
	"fmt"
	"html"
	"html/template"
	"log"
	"net/http"
	"time"
)

func IndexHandler(w http.ResponseWriter, r *http.Request) {
	t, err := template.ParseFiles("index.html")

	if err != nil {
		log.Println(err)
	}

	err = t.Execute(w, nil)

	if err != nil {
		log.Println(err)

	}
}


var count int = 1

func Task(w http.ResponseWriter, r *http.Request) {
	fmt.Printf(" ------ here is Task[%d] ------- \n", count)
	defer r.Body.Close()
 
	// 模拟延时
	time.Sleep(time.Second * 2)
 
	fmt.Fprintf(w, "Response.No.%d: Your request is %q\n\n", count, html.EscapeString(r.URL.Path))
	count++
	answer := `{"status:":"OK"}`
	w.Write([]byte(answer))
}


func Task1(w http.ResponseWriter, r *http.Request) {
	fmt.Printf(" ------ here is Task1[%d] ------- \n", count)
	defer r.Body.Close()
 
	// 模拟延时
	time.Sleep(time.Second * 2)
 
	fmt.Fprintf(w, "Response.No[%d]: Your request is %q\n\n", count, html.EscapeString(r.URL.Path))
	count++
	answer := `{"status:":"OK"}`
	w.Write([]byte(answer))
}


func main() {

	// 调用后台接口
	http.HandleFunc("/hello/world", Task)
	http.HandleFunc("/hello/world1", Task1)
	// 启动静态文件服务
	http.Handle("/template/", http.StripPrefix("/template/", http.FileServer(http.Dir("template")))) 
	http.Handle("/libs/", http.StripPrefix("/libs/", http.FileServer(http.Dir("libs"))))
	
	http.HandleFunc("/index", IndexHandler)
	fmt.Println("服务端口:8000") //控制台输出信息

	err := http.ListenAndServe(":8000", nil) //设置监听的端口

	if err != nil {
		log.Fatal("ListenAndServe: ", err)
	}
}

解释1:go语言中的http.HandleFunc("/index", IndexHandler)相当于,前端访问接口index,后端去调用方法IndexHandler。
相当于java的

@RequestMapping("/index")
public void IndexHandler() {
	// 在此,怀念我那逝去的java
}

等价于go中的

http.HandleFunc("/index", IndexHandler)

项目结构
在这里插入图片描述

index.html代码

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <!-- import CSS -->
  <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
  <link rel="stylesheet" href="template/css/test.css">
</head>
<body>
  <div id="app">
      <span class="mybtn">也无风雨、也无晴</span>
      <el-button @click="httpGet1">get请求</el-button>
    <el-button @click="openPage">Button</el-button>
    <el-dialog :visible.sync="visible" title="Hello world">
      <p>Try Element</p>
    </el-dialog>
  </div>
</body>
  <!-- import Vue before Element -->
  <script src="https://unpkg.com/vue/dist/vue.js"></script>
  <!--script src="./libs/axios-0.16.2.min.js"></script,不知道这个为啥不行,可以把下面这个直接下载下来,打包到项目里-->
  <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
  <script src="./libs/vue/vue-2.2.2.min.js"></script>
  <script src="./libs/jquery/jquery.min.js"></script>
  <!-- import JavaScript -->
  <script src="https://unpkg.com/element-ui/lib/index.js"></script>

  <script>
    new Vue({
      el: '#app',
      data: function() {
        return { visible: false }
      },
      methods:{
        openPage:function(){
            alert("sdfsdfs")
            window.open("./template/user/user.html")
        },
        httpGet1:function(){
          axios({
                method:'get',
                // 对链接前缀进行封装,后台使用的时候直接引用前缀即可
                url:'http://localhost:8000/hello/world'
            }).then(function(resp){
                console.log(resp.data);
            }).catch(resp => {
                console.log('请求失败:'+resp.status+','+resp.statusText);
            });
        }
      }
    })
  </script>
</html>

运行

go run test1.go

在这里插入图片描述

在这里插入图片描述

其中蓝色字体是为了验证不同文件夹下的css的引用

点击下载项目完整代码

vue-element-template打包生成的静态资源404问题

上面的项目是自己手动创建的静态页面和js,html页面里对于js、css的引用都是人为可控的。但是如果是使用的第三方框架,如vue-elemen-template,因为浏览器是不认识.vue文件的,那么开发完成后是将vue等打包成浏览器能解析的js、css、html等文件。打包生成的.html里对于js等的引用路径是可以修改的,但是太过于麻烦,有兴趣的道友可以自行百度,我这里就按它默认生成的资源,然后在go代码里去解决404问题。

工欲善其事,必先利其器。既然是404那么就是静态资源没有加载到,我们就需要了解go是怎么加载静态资源的。那就是函数http.StripPrefix与http.FileServer

我们来看看这行代码

http.Handle("/template/", http.StripPrefix("/template/", http.FileServer(http.Dir("template")))) 

以上http.Handle("/template/",就是相当于一个请求,当前端发起http:www.xxx.com:9527/template时,会进入该方法。即
相当于java的

@RequestMapping("/index")
public void IndexHandler() {
	// 在此,怀念我那逝去的java
}

等价于go中的

http.HandleFunc("/index", IndexHandler)

然后我们看http.StripPrefix方法,它就是拦截请求中含有/template/前缀的资源请求,然后将该前缀替换成http.Dir(“template”)中的template。

http.Dir表示文件的起始路径,空即为当前路径。调用Open方法时,传入的参数需要在前面拼接上该起始路径得到实际文件路径。

http.FileServer的返回值类型是http.Handler,所以需要使用Handle方法注册处理器。http.FileServer将收到的请求路径传给http.Dir的Open方法打开对应的文件或目录进行处理。 在上面的程序中,如果请求路径为/static/hello.html,那么拼接http.Dir的起始路径.,最终会读取路径为./static/hello.html的文件。

有时候,我们想要处理器的注册路径和http.Dir的起始路径不相同。有些工具在打包时会将静态文件输出到public目录中。 这时需要使用http.StripPrefix方法,该方法会将请求路径中特定的前缀去掉,然后再进行处理:如下代码

package main
 
import (
  "log"
  "net/http"
)
 
func main() {
  mux := http.NewServeMux()
  mux.Handle("/static/", http.StripPrefix("/static", http.FileServer(http.Dir("./public"))))
 
 
  server := &http.Server {
    Addr: ":8080",
    Handler: mux,
  }
 
  if err := server.ListenAndServe(); err != nil {
    log.Fatal(err)
  }
}

这时,请求localhost:8080/static/hello.html将会返回./public/hello.html文件。 路径/static/index.html经过处理器http.StripPrefix去掉了前缀/static得到/index.html,然后又加上了http.Dir的起始目录./public得到文件最终路径./public/hello.html。
如果你就想请求static下的文件,那么就将http.Dir中写static即可。
简单点理解就是将含有static的请求拦截,并将http.Dir中的路径替换掉http.StripPrefix中的路径,拼接成新的文件路径然后相应给前端。

好了,大致原理我们明白了。那么实际操作一下,看我的代码。
目录结构
在这里插入图片描述
dist文件夹结构
在这里插入图片描述
index.html页面的代码
在这里插入图片描述
,我们可以看到它打包生成后对静态文件的应用全部都是以static开头的,那么在浏览器加载静态资源的时候,请求的路径就是

GET http://127.0.0.1:8090/static/js/app.js

在这里插入图片描述
这样的请求路径显然是请求不到数据的,那么我们只需要将http://127.0.0.1:8090/static/js/app.js的请求路径修改为
http://127.0.0.1:8090/src/views/vue-element-template/dist/static/js/app.js即可。也就是我们上面分析的将static的请求拦截并且替换路径即可,
我们的项目文件路径是/src/views/vue-element-template/dist/static/
就一行代码,

// 启动静态文件服务
mux.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("./src/views/vue-element-template/dist/static/")))) 

vscode里切换到main.go所在的路径,运行

go run main.go

在这里插入图片描述

再次打开浏览器,问题解决

在这里插入图片描述
此处贴出部分代码
main.go

package main

import (
	"fmt"
	"engine_stability_platform/src/app/httpServer"
)
 
func main() {
	fmt.Println("main.....")
	httpServer.Start()
}

httpServer.go

package httpServer

import (
	"fmt"
	. "fmt"
	"html"
	"html/template"
	"net/http"
)


func IndexHandler(w http.ResponseWriter, r *http.Request) {
	t, err := template.ParseFiles("src/views/vue-element-template/dist/index.html")
	if err != nil {
		fmt.Println(err)
	}

	err = t.Execute(w, nil)
	if err != nil {
		fmt.Println(err)
	}
}
var count int = 1
// 测试demo
func Task(w http.ResponseWriter, r *http.Request) {
	Printf(" ------ here is Task[%d] ------- \n", count)
	Fprintf(w, "Response.No.%d: Your request is %q\n\n", count, html.EscapeString(r.URL.Path))
	count++
	answer := `{"status:":"OK"}`
	w.Write([]byte(answer))
}
 
func Task1(w http.ResponseWriter, r *http.Request) {
	Printf(" ------ here is Task1[%d] ------- \n", count)
	Fprintf(w, "Response.No[%d]: Your request is %q\n\n", count, html.EscapeString(r.URL.Path))
	count++
	answer := `{"status:":"OK"}`
	w.Write([]byte(answer))
}
var server *http.Server

func Start() {
	Println("===== This is http server =====")

	mux := http.NewServeMux()
	mux.HandleFunc("/hello/world", Task)
	mux.HandleFunc("/hello/world1", Task1)
	// 启动静态文件服务
	mux.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("./src/views/vue-element-template/dist/static/"))))
	mux.HandleFunc("/index", IndexHandler)

	if server != nil {
		// 避免重复start server 端口泄露
		server.Close()
	}
	// 设置服务器
	server := &http.Server{
		Addr: "127.0.0.1:8090",
		Handler: mux,
	}
	// 设置服务器监听端口
	server.ListenAndServe()
}

index.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
    <link rel="icon" href="favicon.ico">
    <title>Vue Admin Template</title>
  <link href="static/js/app.js" rel="preload" as="script"><link href="static/js/chunk-elementUI.js" rel="preload" as="script"><link href="static/js/chunk-libs.js" rel="preload" as="script"><link href="static/js/runtime.js" rel="preload" as="script"></head>
  <body>
    <noscript>
      <strong>We're sorry but Vue Admin Template doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
    </noscript>
    <div id="app"></div>
    <!-- built files will be auto injected -->
  <script type="text/javascript" src="static/js/runtime.js"></script><script type="text/javascript" src="static/js/chunk-elementUI.js"></script><script type="text/javascript" src="static/js/chunk-libs.js"></script><script type="text/javascript" src="static/js/app.js"></script></body>
</html>

补充:vue-element-template生成的资源文件夹也可以在vue.config.js里进行更改
在这里插入图片描述

点击下载项目完整代码

参考文章:https://blog.csdn.net/whatday/article/details/109747385?utm_medium=distribute.pc_relevant.none-task-blog-2defaultbaidujs_title~default-0.no_search_link&spm=1001.2101.3001.4242.1

Logo

前往低代码交流专区

更多推荐