Gorilla Golang Pathprefix не обслуживает файлы - PullRequest
0 голосов
/ 05 сентября 2018

У меня есть файл в папке files, расположенный в корне моего каталога проекта Golang, который называется test.jpg. Так что это будет ./files/test.jpg, что я хочу служить своему клиенту, и у меня возникли трудности.

Мой проект golang находится в файле Docker со следующим приложенным томом. (В основном это говорит о том, что /go/.../webserver в контейнере Docker может читать и записывать из ./ на сервере)

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 }

, который приходит из простого http-запроса js с использованием пакета 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, но в этом случае он игнорирует этот маршрут, и есть промежуточное программное обеспечение для обработки 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 пуст). Просто к вашему сведению, что я подтвердил работоспособность, и это не решает проблему.

Ответы [ 3 ]

0 голосов
/ 05 сентября 2018

Я обычно просто объединяю файловые ресурсы в мое скомпилированное приложение. Затем приложение будет запускаться и извлекать ресурсы одинаково, независимо от того, выполняете ли вы его в контейнере или локально. Вот ссылка на один подход. Я использовал go-bindata в прошлом, но похоже, что этот пакет больше не поддерживается, но доступно множество альтернатив .

0 голосов
/ 05 сентября 2018

Итак, это не очень хорошее решение, но оно работает (на данный момент). Я видел этот пост: Голанг. Что использовать? http.ServeFile (..) или 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, чтобы предотвратить 1337h4x0rZ. Если кто-нибудь знает, как настроить pathprefix и запустить его, пожалуйста, дайте мне знать, и я смогу провести рефакторинг. Спасибо всем, кто помог!

0 голосов
/ 05 сентября 2018

Можете ли вы исключить из этого клиента 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/... доступен для чтения пользователю, под которым запущено ваше приложение.
...