【问题标题】:Gorilla Golang Pathprefix not serving filesGorilla Golang Pathprefix 不提供文件
【发布时间】:2019-02-10 23:27:47
【问题描述】:

我在 Golang 项目目录的根目录中的文件夹 files 中有一个文件,名为 test.jpg。所以那将是./files/test.jpg,我想为我的前端服务,但我遇到了困难。

我的 golang 项目位于一个 docker 文件中,并附有以下卷。 (基本上就是说docker容器中的/go/.../webserver可以读写服务器上的./)

volumes:
  - ./:/go/src/github.com/patientplatypus/webserver/

我使用gorilla/mux 进行路由,定义如下:

r := mux.NewRouter()

以下是我尝试正确格式化 PathPrefix 的一些尝试:

r.PathPrefix("/files/").Handler(http.StripPrefix("/files/", 
http.FileServer(http.Dir("/go/src/github.com/patientplatypus/webserver/files/"))))

或

r.PathPrefix("/files").Handler(http.FileServer(http.Dir("./files/")))

或

r.PathPrefix("/files/").Handler(http.StripPrefix("/files/",  
http.FileServer(http.Dir("./"))))

或

r.PathPrefix("/files/").Handler(http.FileServer(
http.Dir("/go/src/github.com/patientplatypus/webserver/")))

我之前使用以下命令成功写入服务器:

newPath := filepath.Join("/go/src/github.com/patientplatypus/webserver/files", 
"test.jpg")
newFile, err := os.Create(newPath)

所以我的直觉是我的第一次尝试应该是正确的,指定了整个/go/.../files/ 路径。

在任何情况下,我的每次尝试都成功地将200OK 返回到我的前端,并带有一个空的 response.data,如下所示:

Object { data: "", status: 200, statusText: "OK",
headers: {…}, config: {…}, request: XMLHttpRequest }

它来自一个简单的 js 前端 http 请求,使用 axios 包:

        axios({
            method: 'get',
            url: 'http://localhost:8000/files/test.jpg',
        })
        .then(response => {
            //handle success
            console.log("inside return for test.jpg and value 
            of response: ")
            console.log(response);
            console.log("value of response.data: ")
            console.log(response.data)
            this.image = response.data;
        })
        .catch(function (error) {
            //handle error
            console.log(error);
        });

我对为什么会发生这种情况的唯一猜测是它看不到文件,因此什么也不返回。

对于这样一个看似微不足道的问题,我处于猜测和检查阶段,不知道如何进一步调试。如果有人有任何想法,请告诉我。

谢谢!

编辑:

为了完全清楚,这里是我的 main.go 文件的全部(只有 150 行)以及所有路由。有一个处理 JWT auth 的中间件,但是在这种情况下它忽略了这条路由,并且有处理 CORS 的中间件。

有问题的行突出显示:https://gist.github.com/patientplatypus/36230e665051465cd51291e17825f1f5#file-main-go-L122。

另外,这是我的 docker-compose 文件,它显示了卷是什么(请忽略启动 postgres 的 sleep 命令 - 我知道这不是理想的实现)

https://gist.github.com/patientplatypus/2569550f667c0bee51287149d1c49568.

应该没有其他必要的调试信息。

另外...有些人希望我证明文件存在于容器中。

patientplatypus:~/Documents/zennify.me:11:49:09$docker exec 
backend_app_1 ls /go/src/github.com/patientplatypus/webserver/files
test.jpg

表明确实如此。

澄清:

我没有正确使用 Axios 来缓冲数组并获取图像。该工作的一个示例在这里:

        //working example image
        var imageurl = 'https://avatars2.githubusercontent.com/u/5302751?v=3&s=88';
        //my empty server response
        //var imageurl = 'http://localhost:8000/files/test.jpg';
        axios.get(imageurl, {
            responseType: 'arraybuffer'
        })
        .then( response => {
            console.log('value of response: ', response);
            console.log('value of response.data: ', response.data);
            const base64 = btoa(
                new Uint8Array(response.data).reduce(
                    (data, byte) => data + String.fromCharCode(byte),
                    '',
                ),
            );
            console.log('value of base64: ', base64);
            this.image = "data:;base64," + base64 
        });

但是,这并没有改变 golang 似乎没有返回任何数据(response.data 为空)的潜在问题。仅供参考,我已确认 axios 可以正常工作,但这并不能解决问题。

【问题讨论】:

    标签: file http go gorilla fileserver


    【解决方案1】:

    你能从中消除 JavaScript 客户端,并发出一个简单的curl 请求吗?将图像替换为简单的文本文件,以消除任何可能的 Content-Type / MIME 检测问题。

    (略微)改编gorilla/mux 文档中发布的示例:https://github.com/gorilla/mux#static-files

    代码

    func main() {
        var dir string
    
        flag.StringVar(&dir, "dir", ".", "the directory to serve files from. Defaults to the current dir")
        flag.Parse()
        r := mux.NewRouter()
    
        r.PathPrefix("/files/").Handler(
            http.StripPrefix("/files/",
                http.FileServer(
                    http.Dir(dir),
                ),
            ),
        )
    
        addr := "127.0.0.1:8000"
        srv := &http.Server{
            Handler:      r,
            Addr:         addr,
            WriteTimeout: 15 * time.Second,
            ReadTimeout:  15 * time.Second,
        }
    
        log.Printf("listening on %s", addr)
        log.Fatal(srv.ListenAndServe())
    }
    

    运行服务器

    ➜  /mnt/c/Users/matt/Dropbox  go run static.go -dir="/home/matt/go/src/github.com/gorilla/mux"
    2018/09/05 12:31:28 listening on 127.0.0.1:8000
    

    获取文件

    ➜  ~  curl -sv localhost:8000/files/mux.go | head
    *   Trying 127.0.0.1...
    * Connected to localhost (127.0.0.1) port 8000 (#0)
    > GET /files/mux.go HTTP/1.1
    > Host: localhost:8000
    > User-Agent: curl/7.47.0
    > Accept: */*
    >
    < HTTP/1.1 200 OK
    < Accept-Ranges: bytes
    < Content-Length: 17473
    < Content-Type: text/plain; charset=utf-8
    < Last-Modified: Mon, 03 Sep 2018 14:33:19 GMT
    < Date: Wed, 05 Sep 2018 19:34:13 GMT
    <
    { [16384 bytes data]
    * Connection #0 to host localhost left intact
    // Copyright 2012 The Gorilla Authors. All rights reserved.
    // Use of this source code is governed by a BSD-style
    // license that can be found in the LICENSE file.
    
    package mux
    
    import (
            "errors"
            "fmt"
            "net/http"
    

    请注意,实现此目的的“正确”方法是根据您的第一个示例:

    r.PathPrefix("/files/").Handler(http.StripPrefix("/files/", 
    http.FileServer(http.Dir("/go/src/github.com/patientplatypus/webserver/files/"))))
    
    • 从路径中去掉 /files/ 前缀,这样文件服务器就不会尝试查找 /files/go/src/...。
    • 确保/go/src/... 正确 - 您提供的是文件系统根目录的绝对路径,而不是您的主目录(这是您的意图吗?)
    • 如果这是您的意图,请确保运行您的应用程序的用户可以读取 /go/src/...。

    【讨论】:

    • 所以 dir 不起作用 ~ r.PathPrefix("/files/").Handler(http.StripPrefix("/files/", http.FileServer(http.Dir(dir)))) 导致 ./main.go:123: undefined: dir。据我所知 dir 不是保留字。我会考虑通过邮递员打电话,看看会发生什么。编辑:oic - dir 只是 === '.'。嗯.....
    • dir 是一个标志,所以不要省略我的示例代码的一部分。它默认为当前目录 - . - 但在传递标志时会被覆盖,就像我在示例中所做的那样。
    • ooooohhhhhhhhhhh 有道理。
    • 所以,如果我在存在blah.txt 的地方使用r.PathPrefix("/files/").Handler(http.StripPrefix("/files/", http.FileServer(http.Dir("/go/src/github.com/patientplatypus/webserver/files/")))) 和邮递员http://localhost:8000/files/blah.txt,我会得到没有正文的200OK。如果我对 blah2.txt 不存在 的 blah2.txt 执行相同操作,我会得到相同的结果。似乎有些不对劲。 (blah.txt 有一些 helloworld 顺便说一句)。
    • 我的建议:清理你的帖子。删除 JavaScript 部分。专注于 Go 部分,并展示一个可以复制粘贴并运行的最小示例。你还没有这样做,所以这里还有其他东西 - 也许是另一条路线?
    【解决方案2】:

    我通常只是将文件资产捆绑到我编译的应用程序中。然后,无论您是在容器中还是在本地运行,应用程序都将以相同的方式运行和检索资产。这是a link 的一种方法。我过去使用过 go-bindata,但似乎不再维护这个包但有很多 alternatives available。

    【讨论】:

      【解决方案3】:

      所以,这不是一个很好的解决方案,但它(目前)有效。我看到了这个帖子:Golang. What to use? http.ServeFile(..) or http.FileServer(..)?,显然您可以使用较低级别的 api servefile 而不是添加了保护的文件服务器。

      所以我可以使用

      r.HandleFunc("/files/{filename}", util.ServeFiles)

      和

      func ServeFiles(w http.ResponseWriter, req *http.Request){
          fmt.Println("inside ServeFiles")
          vars := mux.Vars(req)
          fileloc := "/go/src/github.com/patientplatypus/webserver/files"+"/"+vars["filename"]
          http.ServeFile(w, req, fileloc)
      }
      

      这又不是一个很好的解决方案,我也不高兴 - 我必须在 get 请求参数中传递一些 auth 内容,以防止出现 1337h4x0rZ。如果有人知道如何启动和运行路径前缀,请告诉我,我可以重构。感谢所有帮助过的人!

      【讨论】:

      【解决方案4】:

      我和你在同一个页面上,完全一样,我一直在调查这件事,让它能工作一整天。我卷曲了,它还给了我 200 个字节,正如您在上面的 cmets 中提到的那样。我在责怪码头工人。

      它终于奏效了,唯一的 (...) 变化是我删除了 http.Dir() 中的尾部斜杠

      例如:在您的示例中,将其设为:http.FileServer(http.Dir("/go/src/github.com/patientplatypus/webserver/files")))),不要添加最后一个斜杠以使其成为 .../files/

      它奏效了。它显示了图片,以及卷曲结果:

      HTTP/2 200 
       accept-ranges: bytes
       content-type: image/png
       last-modified: Tue, 15 Oct 2019 22:27:48 GMT
       content-length: 107095
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2023-03-11
        • 2018-11-12
        • 2018-07-30
        • 2018-02-07
        • 1970-01-01
        • 2022-01-27
        • 2017-10-10
        • 2019-01-09
        相关资源
        最近更新 更多