Mocking HTTPS-Antworten im Go
Ich versuche zum schreiben von tests für ein Paket, das die Anfragen an einen web service. Ich bin in Probleme laufen, wahrscheinlich wegen meiner mangelnden Verständnis von TLS.
Derzeit mein test sieht wie folgt aus:
func TestSimple() {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(200)
fmt.Fprintf(w, `{ "fake" : "json data here" }`)
}))
transport := &http.Transport{
Proxy: func(req *http.Request) (*url.URL, error) {
return url.Parse(server.URL)
},
}
//Client is the type in my package that makes requests
client := Client{
c: http.Client{Transport: transport},
}
client.DoRequest() //...
}
Mein Paket ist ein Paket-variable (ich möchte, dass es eine Konstante..) für die Basis-Adresse des web service für die Abfrage aus. Es ist eine https-URL. Der test-server, den ich oben erstellt, ist schlicht HTTP, kein TLS.
Standardmäßig, mein test fehlschlägt mit der Fehlermeldung "tls: erste Datensatz nicht Aussehen wie ein TLS-handshake."
Zu bekommen dies funktioniert, meine tests ändern Sie die package-variable, um eine plain-http-URL anstelle von https, bevor Sie die Abfrage.
Gibt es eine Möglichkeit, um dieses? Ich kann die Paket-variable eine Konstante (https), und entweder einen http.Transport
dass "downgrades" auf unverschlüsselte HTTP, oder verwenden Sie httptest.NewTLSServer()
statt?
(Wenn ich versuche, mit NewTLSServer()
bekomme ich "http: TLS-handshake-Fehler, die von 127.0.0.1:45678: tls: oversized-Datensatz empfangen mit Länge 20037")
- Tun Sie wirklich brauchen, zu verspotten, eine TLS-Anfrage? net/http hat umfangreiche tests, also Tests gegen einen lokalen HTTPS-gehosteten test-Implementierung ist eher überflüssig. Tests auf HTTP-direkt ist semantisch äquivalent.
- Nein. In der Tat bin ich Spott gegen HTTP jetzt. Ich gerade nicht, wie die Problemumgehung ich verwenden, um zu erzwingen, HTTP. Etwas wird automatisch versuchen, die TLS verwenden, da die Anfrage-URL mit https beginnt. Ich würde lieben, um dieses Verhalten zu deaktivieren, nur für meine tests.
- Okay, in diesem Fall können Sie erstellen, die eine Implementierung einer http.RoundTripper, die tut, was Sie wollen (wie behandelt https:// als ob es eine http-url) -- Sie können sogar eine benutzerdefinierte RoundTripper zu laufen, nur ein mock http.Handler direkt, ohne Umweg über httptest.Server. Alles, was Sie zu tun haben, dann ist
http.DefaultClient.Transport = CustomRoundTripper
. - Alternativ können Sie golang.org/pkg/net/http/httptest/#NewTLSServer
- Die benutzerdefinierte
http.RoundTripper
funktioniert wie ein Charme. Sie sollten konvertieren Sie Ihren Kommentar zu einer Antwort, damit ich das annehmen kann. - Waren Sie jemals in der Lage, herauszufinden, warum Sie immer waren übergroße Datensätze zurück, die mit
NewTLSServer
?
Du musst angemeldet sein, um einen Kommentar abzugeben.
Meisten das Verhalten in
net/http
werden kann, verspottet, erweitert oder verändert werden. Obwohlhttp.Client
einen konkreten Typ implementiert, dass HTTP-client, der Semantik, werden alle Felder exportiert werden und können angepasst werden.Den
Client.Transport
Bereich, insbesondere können ersetzt werden, um den Kunden etwas tun mit benutzerdefinierten Protokollen (wie ftp://oder file://), um eine direkte Verbindung zu lokalen Handler (ohne die Generierung der HTTP-Protokoll-bytes oder senden alles über das Netzwerk).Die client-Funktionen, wie
http.Get
, alle nutzen die exportiertehttp.DefaultClient
Paket-variable (die Sie ändern können), also code, der nutzt diese Komfort-Funktionen hat nicht, zum Beispiel, müssen geändert werden, um Methoden aufzurufen, die auf einem benutzerdefinierten Client-Variablen. Beachten Sie, dass es unangemessen wäre, zu modifizieren Globale Verhalten in eine öffentlich zugängliche Bibliothek, ist es sehr nützlich, dies zu tun in Anwendungen und tests (einschließlich Bibliothek tests).http://play.golang.org/p/afljO086iB enthält eine benutzerdefinierte
http.RoundTripper
schreibt, dass die request-URL, so dass Sie werden weitergeleitet zu einem lokal gehostetenhttptest.Server
, und ein weiteres Beispiel, das direkt übergibt die Anforderung an einehttp.Handler
zusammen mit einer benutzerdefiniertenhttp.ResponseWriter
umgesetzt werden, um zu erstellen einhttp.Response
. Der zweite Ansatz ist nicht so fleißig wie der erste (nicht füllen Sie so viele Felder in den Resonanz-Wert) ist aber effizienter, und sollte kompatibel genug, um die Arbeit mit den meisten Handler und client-Anrufer.Den oben verlinkten code ist unten enthalten sowie:
Der Grund, warum man immer die Fehler
http: TLS handshake error from 127.0.0.1:45678: tls: oversized record received with length 20037
ist da https erfordert einen domain-Namen (nicht IP-Adresse). Domain-Namen sind SSL-Zertifikate zugeordnet sind.Start der httptest server im TLS-Modus mit eigenen certs
Ein gültiges SSL-Zertifikat für eine Verbindung sind die Optionen:
Keine Cert
Wenn Sie nicht liefern Ihre eigenen cert, dann ein
example.com
cert geladen wird, als Standard.Self-Signed Cert
Erstellung eines Test-cert können, verwenden Sie den mitgelieferten selbst-signiertes Zertifikat-generator bei
$GOROOT/src/crypto/tls/generate_cert.go --host "*.domain.name"
Erhalten Sie
x509: certificate signed by unknown authority
Warnungen, weil es selbst signiert, so dass Sie brauchen, um Ihre Kunden zu überspringen, diese Warnungen, indem Sie die folgende, um Ihre http.Transport-Feld:Gültigen Real-Cert
Schließlich, wenn Sie gehen, um einen real-cert, dann speichern Sie die gültigen cert und key, wo Sie geladen werden können.
Den key hier ist die Verwendung
server.URL = https://sub.domain.com
zur Versorgung Ihrer eigenen domain.