Как отладить httputil.NewSingleHostReverseProxy - PullRequest
0 голосов
/ 25 октября 2018

Проблема:

  1. Я обращаюсь к HTTPS-адресу.
  2. Я хочу понять, почему удаление req.Host = req.URL.Host приводит к сбою.Вместо того, чтобы возвращать {"Code":"OBRI.FR.Request.Invalid","Id":"c37baec213dd1227","Message":"An error happened when parsing the request arguments","Errors":[{"ErrorCode":"UK.OBIE.Header.Missing","Message":"Missing request header 'x-fapi-financial-id' for method parameter of type String","Url":"https://docs.ob.forgerock.financial/errors#UK.OBIE.Header.Missing"}]}, он возвращает 404.
  3. Я хочу отследить вызов, который совершает прокси, возвращенный с httputil. NewSingleHostReverseProxy, когда я раскомментирую строку req.Host = req.URL.Host.

Учитывая запрос как таковой:

$ curl http://localhost:8989/open-banking/v2.0/accounts

И код ниже (main.go):

package main

import (
    "log"
    "net/http"
    "net/http/httputil"
    "net/url"
)

func main() {
    target, err := url.Parse("https://rs.aspsp.ob.forgerock.financial:443")
    log.Printf("forwarding to -> %s%s\n", target.Scheme, target.Host)

    if err != nil {
        log.Fatal(err)
    }
    proxy := httputil.NewSingleHostReverseProxy(target)

    http.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
        // https://stackoverflow.com/questions/38016477/reverse-proxy-does-not-work
        // https://forum.golangbridge.org/t/explain-how-reverse-proxy-work/6492/7
        // https://stackoverflow.com/questions/34745654/golang-reverseproxy-with-apache2-sni-hostname-error

        req.Host = req.URL.Host // if you remove this line the request will fail... I want to debug why.

        proxy.ServeHTTP(w, req)
    })

    err = http.ListenAndServe(":8989", nil)
    if err != nil {
        panic(err)
    }
}

1 Ответ

0 голосов
/ 26 октября 2018

Установите в поле proxy.Transport реализацию, которая выводит запрос перед делегированием в транспорт по умолчанию:

package main

import (
        "fmt"
        "log"
        "net/http"
        "net/http/httputil"
        "net/url"
)

type DebugTransport struct{}

func (DebugTransport) RoundTrip(r *http.Request) (*http.Response, error) {
        b, err := httputil.DumpRequestOut(r, false)
        if err != nil {
                return nil, err
        }
        fmt.Println(string(b))
        return http.DefaultTransport.RoundTrip(r)
}

func main() {
        target, _ := url.Parse("https://example.com:443")
        log.Printf("forwarding to -> %s\n", target)

        proxy := httputil.NewSingleHostReverseProxy(target)

        proxy.Transport = DebugTransport{}

        http.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
                req.Host = req.URL.Host

                proxy.ServeHTTP(w, req)
        })

        log.Fatal(http.ListenAndServe(":8989", nil))
}

Вывод из этой программы выглядит примерно так:

2018/10/26 13:06:35 forwarding to -> https://example.com:443
GET / HTTP/1.1
Host: example.com:443
User-Agent: HTTPie/0.9.4
Accept: */*
Accept-Encoding: gzip, deflate
X-Forwarded-For: 127.0.0.1

Или, после удаления назначения req.Host:

2018/10/26 13:06:54 forwarding to -> https://example.com:443
GET / HTTP/1.1
Host: localhost:8989
User-Agent: HTTPie/0.9.4
Accept: */*
Accept-Encoding: gzip, deflate
X-Forwarded-For: 127.0.0.1

Поскольку заголовок хоста очень часто используется веб-серверами для направления запроса на правильный виртуальный хост или внутренний сервер, имеет смысл, что неожиданный хостзаголовок ("localhost: 8989" в приведенном выше примере) заставляет сервер ответить 404.

Установка заголовка узла с помощью httputil.ReverseProxy обычно выполняется с помощью функции Director:

    target, err := url.Parse("https://example.com:443")
    if err != nil {
            log.Fatal(err)
    }
    log.Printf("forwarding to -> %s\n", target)

    proxy := httputil.NewSingleHostReverseProxy(target)

    d := proxy.Director
    proxy.Director = func(r *http.Request) {
            d(r) // call default director

            r.Host = target.Host // set Host header as expected by target
    }

    log.Fatal(http.ListenAndServe(":8989", proxy))
...