Вложенный ServeMux всегда возвращает «301 перемещено навсегда» - PullRequest
6 голосов
/ 21 февраля 2020

При использовании вложенного http.ServeMux для определения конечных точек моего сервера я столкнулся с этой проблемой: обработчик всегда отвечал бы «301 перемещен навсегда» на любой запрос, даже если путь URL должен совпадать.

Пример:

package main

import "net/http"

func main() {
    api := http.NewServeMux()
    api.HandleFunc("ping", func(w http.ResponseWriter, r *http.Request) {
        w.Write([]byte("pong\n"))
    })

    root := http.NewServeMux()
    root.Handle("/api/", http.StripPrefix("/api/", api))
    http.ListenAndServe(":8080", root)
}

При попытке доступа к /api/ping сервер перенаправляет на /ping (что, конечно, возвращает 404). То же самое происходит с любым маршрутом под /api/ - /api/foo, перенаправляющим на /foo.

Я использую Go 1.13 и curl 7.58.

Ответы [ 3 ]

4 голосов
/ 22 февраля 2020

Редактировать : чтобы упростить тестирование в Firefox, я отключил кеширование .. в противном случае мне пришлось бы вручную очищать кеш для получения точных результатов. У меня не было такой же проблемы при использовании Chrome, хотя.

enter image description here


Имейте в виду, я новичок в Go но эта проблема сводила меня с ума ... Я испытывал то же поведение, что и вы (очевидно) ..

Казалось бы, Go / http требователен к форматированию шаблонов ..

Я возился с этим около часа и, наконец, смог получить рабочий пример, используя следующий код:

// Working Code
package main

import "net/http"

func main() {
    root := http.NewServeMux()
    api := http.NewServeMux()

    api.HandleFunc("/ping", myHandlerFunc)

    root.Handle("/api/", http.StripPrefix("/api", api))

    http.ListenAndServe(":8080", root)
}

func myHandlerFunc(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("pong\n"))
}

Я пробовал столько разных конфигураций, сколько вы можете себе представить (до / косые черты коснулись), и приведенный выше код был единственным способом заставить его работать ..

В частности, ссылаясь на:

// Leading forward slash on /ping
api.HandleFunc("/ping", myHandlerFunc)

// The first /api/ is surrounded in forward slashes,
// the second /api only contains a leading forward slash
root.Handle("/api/", http.StripPrefix("/api", api))

Изменение кода вызывает 404-е .. .

// DOES NOT WORK!!
package main

import "net/http"

func main() {
    root := http.NewServeMux()
    api := http.NewServeMux()

    api.HandleFunc("/ping", myHandlerFunc)

    root.Handle("/api", http.StripPrefix("/api", api))

    http.ListenAndServe(":8080", root)
}

func myHandlerFunc(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("pong\n"))
}

Надеюсь, это поможет! Приветствия

1 голос
/ 22 февраля 2020

Я только что имел дело с этим на днях. Я думаю, ServeMux ожидает корневые деревья (начиная с /), или он интерпретирует путь как имя хоста.

Фиксированные имена шаблонов, корневые пути, например "/favicon.ico", или корневые поддеревья, такие как "/ images /" .... Шаблоны могут необязательно начинаться с имени хоста, ограничивая совпадения с URL-адресами только на этом хосте.

Я предполагаю, что интерпретируется ping как имя хоста, и это вызывает странность в том, как работает servemux.

В других решениях, которые написали люди, они меняются вокруг позиций /, так что маршрут ping заканчивается до /ping.

Лично мне не понравилось, что я должен был написать /api/ в одном месте и /api в другом месте. В моем конкретном случае я решил использовать что-то вроде:

root.Handle(createAPIEndpoints("/api/"))
...
func createAPIEndpoints(base string) (string, *http.ServeMux) {

    mux := http.NewServeMux()
    mux.HandleFunc(base+"ping", func(...){...})
    mux.HandleFunc(base+"another", func(...){...})

    // another buried servemux
    mux.Handle(createMoreEndpoints(base+"more/"))

    return base, mux
}

Однако, если вы хотите обернуть обработчики обработчиками (например, использовать StripPrefix или другие виды промежуточного программного обеспечения, это работает не так хорошо из-за возврата 2 значений.

0 голосов
/ 21 февраля 2020

Вы настраиваете сервер, но фактически не используете его.

Поскольку вы настроили api, вы должны передать его ListenAndServe.

func main() {
    api := http.NewServeMux()
    api.HandleFunc("/ping", func(w http.ResponseWriter, r *http.Request) {
        w.Write([]byte("pong\n"))
    })

    http.Handle("/api/", http.StripPrefix("/api", api))
    http.ListenAndServe(":8080", api)
}

301 происходит, когда ваш StripPrefix приводит к необработанному маршруту.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...