我在位于我的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 }
这是来自使用axios
包的简单的js frontside http请求:
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文件,它显示了卷的内容(请忽略sleep命令来启动postgres - 我知道它不是理想的实现)
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为空)的潜在问题。仅供参考,我已经确认了一个有效的工作原理并且无法解决问题。
你可以从中消除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/...
。我通常只将文件资产捆绑到我编译的应用程序中。然后,无论您是在容器中还是在本地运行,应用程序都将以相同的方式运行和检索资产。这是a link的一种方法。我过去曾经使用过go-bindata但看起来好像这个包不再维护但是有很多alternatives available。
所以,这不是一个很好的解决方案,但它可以工作(目前)。我看到这篇文章: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。如果有人知道如何启动和运行pathprefix,请让我知道,我可以重构。谢谢大家的帮助!