Übergeben von Kontext an Schnittstellenmethoden

8

Etwas inspiriert von diesem Artikel in der letzten Woche, spiele ich mit dem Refactoring einer Anwendung Ich muss den Kontext (DB-Pools, Sitzungsspeicher usw.) explizit an meine Handler weitergeben.

Ein Problem, das ich habe, ist jedoch, dass ohne eine globale Vorlagenzuordnung die ServeHTTP -Methode für meinen benutzerdefinierten Handlertyp (um http.Handler zu erfüllen) nicht mehr auf die Map zugreifen kann, um eine Vorlage zu rendern.

Ich muss entweder die globale Variable templates beibehalten oder meinen benutzerdefinierten Handlertyp als Struktur neu definieren.

Gibt es einen besseren Weg, dies zu erreichen?

func.go

%Vor%

struct.go

%Vor%

Gibt es eine sauberere Methode, die context -Instanz an ServeHTTP zu übergeben?

Beachten Sie, dass go build -gcflags=-m zeigt, dass keine der beiden Optionen in Heapzuweisungs-Teams schlechter ist: Das &appContext Literal tritt in beiden Fällen (wie erwartet) in den Heapspeicher zurück, obwohl die struct-basierte Option meiner Interpretation entspricht Übergeben Sie bei jeder Anfrage einen zweiten Zeiger (an context ) - Korrigieren Sie mich, wenn ich hier falsch liege , denn ich würde es lieben, dies besser zu verstehen.

Ich bin nicht ganz davon überzeugt, dass Globals im Paket main (dh nicht lib) schlecht sind, vorausgesetzt, dass sie auf diese Weise sicher sind (read only / mutexes / a pool), aber ich mag Klarheit, die ich explizit weitergeben muss Kontext bietet.

    
elithrar 12.07.2014, 15:51
quelle

2 Antworten

4

Nach einigen Diskussionen mit ein paar hilfreichen Gophern auf # go-nuts, geht es bei der obigen Methode um "so gut wie es geht" von dem, was ich erkennen kann.

  • Das "con" mit dieser Methode ist, dass wir einen Verweis auf unseren Kontext struct zweimal übergeben: einmal als Zeigerempfänger in unserer Methode und wiederum als Strukturelement, auf das ServeHTTP zugreifen kann es auch.
  • Das "pro" ist, dass wir unseren struct-Typ erweitern können, um eine Anfragekontextstruktur zu akzeptieren, wenn wir das möchten (wie gocraft / Web tut).

Beachten Sie, dass wir unsere Handler nicht als Methoden für appHandler , d. h. func (ah *appHandler) IndexHandler(...) definieren können, da wir den Handler in ServeHTTP (d. h. ah.h(w,r) ) aufrufen müssen.

%Vor%

Dies ist auch, am wichtigsten, vollständig kompatibel mit http.Handler , so dass wir unsere Handler-Struktur immer noch mit generischer Middleware umschließen können: gzipHandler(appHandler{context.IndexHandler, context}) .

(Ich bin immer noch offen für andere Vorschläge!)

Aktualisieren

Dank dieser großartigen Antwort auf Reddit konnte ich eine bessere Lösung finden das erforderte nicht, zwei Referenzen auf meine context Instanz pro Anfrage zu übergeben.

Stattdessen erstellen wir nur eine Struktur, die einen eingebetteten Kontext und unseren Handler-Typ akzeptiert, und wir erfüllen trotzdem die http.Handler -Schnittstelle dank ServeHTTP . Handler sind keine Methoden mehr auf unserem appContext -Typ, sondern akzeptieren sie einfach als Parameter, was zu einer etwas längeren Funktionssignatur führt, aber dennoch "offensichtlich" und einfach zu lesen ist. Wenn wir uns Gedanken über das "Tippen" machen, brechen wir sogar, weil wir keinen Empfänger mehr haben, um den wir uns kümmern müssen.

%Vor%     
elithrar 14.07.2014, 01:27
quelle
6

Ich würde eine Schließung verwenden und so etwas tun:

%Vor%

Und benutze einfach das zurückgegebene http.Handler .

Sie müssen nur sicherstellen, dass Ihr appContext goroutine-sicher ist.

    
seong 15.07.2014 11:08
quelle

Tags und Links