gorilla / mux, rs / cors, [justinas / alice](https: // github. Ich werde Ihnen zeigen, wie Sie einen Server erstellen, indem Sie com / justinas / alice kombinieren. Insbesondere als ich versuchte, die anzuwendende Middleware nach dem Pfad zu unterteilen, war ich von CORS abhängig, daher werde ich mich auf den Teil konzentrieren, der damit zusammenhängt. In dem Code, der veröffentlicht werden soll, handelt es sich im Grunde genommen um eine Schreibweise, bei der Fehler ignoriert werden. Schreiben Sie sie daher gegebenenfalls neu. Beachten Sie außerdem, dass "..." im Code einfach Abkürzung bedeutet und keine grammatikalische Bedeutung hat. Seien Sie also beim Kopieren vorsichtig.
tl;dr
Achten Sie auf die OPTIONS-Methode der Preflight-Anfrage.
Es werden einige Beispiele gezeigt, aber da es sich um den in jeder README-Datei beschriebenen Basisinhalt handelt, fahren Sie, falls Sie ihn kennen, mit [Implementierungssubjekt](# Implementierungssubjekt) fort.
gorilla/mux
Hier ist ein Beispiel für einen Server, der mux verwendet.
package main
import (
"encoding/json"
"net/http"
"github.com/gorilla/mux"
)
type Character struct {
Name string `json:"name"`
}
func pilotFunc(w http.ResponseWriter, r *http.Request) {
res, _ := json.Marshal(Character{"Shinji"})
w.WriteHeader(http.StatusOK)
w.Write(res)
}
func angelFunc(w http.ResponseWriter, r *http.Request) {
res, _ := json.Marshal(Character{"Adam"})
w.WriteHeader(http.StatusOK)
w.Write(res)
}
func main() {
r := mux.NewRouter() //r ist*mux.Routertyp
r.Methods("GET").Path("/pilot").HandlerFunc(pilotFunc) // r.zu Routen*mux.Route hinzufügen.
r.Methods("GET").Path("/angel").HandlerFunc(angelFunc) // r.Routen ist[]*mux.Da es sich um einen Routentyp handelt, können Sie immer mehr hinzufügen.
http.ListenAndServe(":8000", r)
}
Damit ist ein kleiner Server fertig.
$ go run main.go
$ curl http://localhost:8000/pilot
{"name": "Shinji"}
Wenn ich jedoch "fetch" aus einem Browser verwende, wird folgende Fehlermeldung angezeigt:
Access to fetch at 'http://localhost:8000/user' from origin 'null' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
rs/cors
Hier kommt rs / cors ins Spiel. Für CORS ist die MDN-Seite leicht zu verstehen. Um CORS zu unterstützen, muss im Antwortheader auf der Serverseite ein geeigneter Wert festgelegt werden. Dafür ist Rs / cors verantwortlich. Ich habe dem vorherigen Beispiel rs / cors hinzugefügt.
import (
...
"github.com/rs/cors"
)
func main() {
r := mux.NewRouter()
r.Methods("GET").Path("/pilot").HandlerFunc(pilotFunc)
r.Methods("GET").Path("/angel").HandlerFunc(angelFunc)
c := cors.Default().Handler(r) //Hinzugefügt.
http.ListenAndServe(":8000", c) //Geändert von r nach c.
}
Sie können CORS nur durch Hinzufügen einer Zeile unterstützen.
justinas/alice
Darüber hinaus ist justinas / alice nützlich, wenn Sie Middleware hinzufügen möchten, die den Inhalt der Anforderung jedes Mal in das Protokoll ausgibt, oder Middleware, die den Wert aus dem Anforderungsheader abruft, bevor Sie die Hauptverarbeitung ausführen. (: //github.com/justinas/alice). Hier ist ein Beispiel für das Erstellen und Hinzufügen von Middleware, die Anforderungsinformationen im Protokoll ausgibt.
import (
...
"log"
"github.com/justinas/alice"
)
func logHandler(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
log.Printf("Method: %v; URL: %v; Protocol: %v", r.Method, r.URL, r.Proto)
h.ServeHTTP(w, r)
})
}
func main() {
r := mux.NewRouter()
r.Methods("GET").Path("/pilot").HandlerFunc(pilotFunc)
r.Methods("GET").Path("/angel").HandlerFunc(angelFunc)
c := cors.Default()
chain := alice.New(c.Handler, logHandler).Then(r) //Hinzugefügt.
http.ListenAndServe(":8000", chain) //Von c zu Kette geändert.
}
Übrigens gorilla / mux, rs / cors, [justinas / alice](https: // github.com/justinas/alice) wird erneut veröffentlicht (die Definitionen von packge, import und struct werden weggelassen).
...
func pilotFunc(w http.ResponseWriter, r *http.Request) {
res, _ := json.Marshal(Character{"Shinji"})
w.WriteHeader(http.StatusOK)
w.Write(res)
}
func angelFunc(w http.ResponseWriter, r *http.Request) {
res, _ := json.Marshal(Character{"Adam"})
w.WriteHeader(http.StatusOK)
w.Write(res)
}
func logHandler(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
log.Printf("Method: %v; URL: %v; Protocol: %v", r.Method, r.URL, r.Proto)
h.ServeHTTP(w, r)
})
}
func main() {
r := mux.NewRouter()
r.Methods("GET").Path("/pilot").HandlerFunc(pilotFunc)
r.Methods("GET").Path("/angel").HandlerFunc(angelFunc)
c := cors.Default()
chain := alice.New(c.Handler, logHandler).Then(r)
http.ListenAndServe(":8000", chain)
}
Bei dieser Methode wird die festgelegte Middleware jedoch auf alle Anforderungen angewendet.
Beispielsweise prüft / pilot
, ob Sie angemeldet sind, und gibt nur Daten zurück, wenn Sie angemeldet sind . / angel
kann jedoch nicht auf Anforderungen antworten, die Daten zurückgeben, selbst wenn Sie nicht angemeldet sind. Mit Qiita können Sie die Artikelseite auch dann sehen, wenn Sie nicht angemeldet sind. Stellen Sie sich jedoch eine Situation vor, in der Sie den Entwurf meiner Seite nur sehen können, wenn Sie angemeldet sind.
Versuchen Sie daher Folgendes. Wie ich bereits sagte, bin ich süchtig nach dem Schreibstil unten (lacht).
type funcHandler struct {
handler func(w http.ResponseWriter, r *http.Request)
}
func (h funcHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
h.handler(w, r)
}
func pilotFunc(w http.ResponseWriter, r *http.Request) {...}
func angelFunc(w http.ResponseWriter, r *http.Request) {...}
func logHandler(h http.Handler) http.Handler {...}
func authHandler(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
log.Println("Authentication")
h.ServeHTTP(w, r)
})
}
func main() {
c := cors.Default()
logChain := alice.New(c.Handler, logHandler)
authChain := logChain.Append(authHandler)
r := mux.NewRouter()
r.Methods("GET").Path("/pilot").Handler(authChain.Then(funcHandler{pilotFunc}))
r.Methods("GET").Path("/angel").Handler(logChain.Then(funcHandler{angelFunc}))
http.ListenAndServe(":8000", r)
}
Nur wenn "Abrufen" zu "/ Pilot" erfolgt, wird "Authentifizierung" an die Standardausgabe ausgegeben. Jetzt ist es möglich, die anzuwendende Middleware nach dem Pfad zu trennen.
$go run main.go
2020/09/29 20:41:18 Method: GET; URL: /pilot; Protocol: HTTP/1.1
2020/09/29 20:41:18 Method: GET; URL: /pilot; Protocol: HTTP/1.1; Authentication
2020/09/29 20:41:18 Method: GET; URL: /angel; Protocol: HTTP/1.1
Ich werde die Erklärung hinterlassen, warum dies süchtig macht, und kurz den Mechanismus des Umschreibens auf diese Weise erläutern. Wenn Sie den Grund sehen möchten, warum Sie zuerst süchtig sind, fahren Sie mit [Grund für die Sucht] fort (# Grund für die Sucht).
Lassen Sie uns zunächst überprüfen, was "http.ListenAndServer" tut, aber [Go] Lesen des net / http-Pakets und Ausführen von http.HandleFunc / items / 1d1c64d05f7e72e31a98) ist ziemlich detailliert, also werde ich es hier werfen. Es scheint, dass die Informationen etwas alt sind und die geschriebene Zeilennummer nicht mit der tatsächlichen Zeilennummer übereinstimmt oder dass der Schreibstil etwas anders ist, aber ich denke, dass es kein Problem beim grundlegenden Verständnis gibt.
Abschließend übergibt "http.ListenAndServe" die empfangene Anforderung im zweiten Argument an "ServeHTTP" (diesmal "mux.Router"). Daher muss das zweite Argument "ServeHTTP" implementieren. "ServeHTTP" ist in "mux.Router" und im "http" -Paket implementiert.
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}
Jede Variable vom Typ "http.Handler" kann das zweite Argument von "ListenAndServe" sein. Rufen Sie in diesem "ServeHTTP" das "ServeHTTP" eines anderen "http.Hanlder" auf, und rufen Sie in diesem "ServeHTTP" das "ServeHTTP" des anderen "http.Hanlder" auf und so weiter. Durch Verketten von .Handler` können Sie Anfragen der Reihe nach bearbeiten.
Mit anderen Worten, Sie können Handler verketten, indem Sie eine Funktion verwenden, die "http.Handler" als Argument verwendet und einen "http.Handler" -Typ zurückgibt, dh Middleware **. Betrachten Sie als Beispiel die Kette von "logHandler" und "authHandler".
chain := logHandler(authHandler(router))
Eine solche Kette kann in Betracht gezogen werden. Mit dieser Methode wird es jedoch schwieriger zu verstehen, wenn die Anzahl der Middleware zunimmt.
chain := alice.New(logHandler, authHandler).Then(router)
Wird kurz geschrieben.
Vergleichen wir hier vor und nach dem Umschreiben, damit die angewendete Middleware je nach Pfad geändert werden kann.
//Vorher ändern
func main() {
r := mux.NewRouter()
r.Methods("GET").Path("/pilot").HandlerFunc(pilotFunc)
r.Methods("GET").Path("/angel").HandlerFunc(angelFunc)
c := cors.Default()
chain := alice.New(c.Handler, logHandler).Then(r)
http.ListenAndServe(":8000", chain)
}
//Nach der veränderung
func main() {
c := cors.Default()
logChain := alice.New(c.Handler, logHandler)
authChain := logChain.Append(authHandler)
r := mux.NewRouter()
r.Methods("GET").Path("/pilot").Handler(authChain.Then(funcHandler{pilotFunc}))
r.Methods("GET").Path("/angel").Handler(logChain.Then(funcHandler{angelFunc}))
http.ListenAndServe(":8000", r)
}
Daher ist der Ablauf, dem die Anforderung vor und nach der Änderung folgt
Bisherige: request -> CORS -> logging -> routing -> pilotFunc or angelFunc
Rückseite: request -> routing -> CORS -> logging (-> auth) -> pilotFunc or angelFunc
Sie können sehen, dass sich die Reihenfolge des Routings geändert hat. Dies ist einer der Gründe, warum ich süchtig danach bin.
Als nächstes werde ich erklären, warum ich von CORS abhängig bin, was das Hauptthema dieses Artikels ist.
Zunächst werde ich eine Implementierung des Authentifizierungsmechanismus beschreiben (Details werden später beschrieben), die dem tatsächlichen etwas näher kommt.
func authHandler(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
token := r.Header.Get("Token")
if token == "" {
w.WriteHeader(http.StatusUnauthorized)
return
}
h.ServeHTTP(w, r)
})
}
package main
import (
"encoding/json"
"log"
"net/http"
"github.com/gorilla/mux"
"github.com/justinas/alice"
"github.com/rs/cors"
)
type Character struct {
Name string `json:"name"`
}
type funcHandler struct {
handler func(w http.ResponseWriter, r *http.Request)
}
func (h funcHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
h.handler(w, r)
}
func pilotFunc(w http.ResponseWriter, r *http.Request) {
res, _ := json.Marshal(Character{"Shinji"})
w.WriteHeader(http.StatusOK)
w.Write(res)
}
func angelFunc(w http.ResponseWriter, r *http.Request) {
res, _ := json.Marshal(Character{"Adam"})
w.WriteHeader(http.StatusOK)
w.Write(res)
}
func logHandler(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
log.Printf("Method: %v; URL: %v; Protocol: %v", r.Method, r.URL, r.Proto)
h.ServeHTTP(w, r)
})
}
func authHandler(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
token := r.Header.Get("Token")
if token == "" {
w.WriteHeader(http.StatusUnauthorized)
return
}
h.ServeHTTP(w, r)
})
}
func main() {
c := cors.Default()
logChain := alice.New(c.Handler, logHandler)
authChain := logChain.Append(authHandler)
r := mux.NewRouter()
r.Methods("GET").Path("/pilot").Handler(authChain.Then(funcHandler{pilotFunc}))
r.Methods("GET").Path("/angel").Handler(logChain.Then(funcHandler{angelFunc}))
http.ListenAndServe(":8000", r)
}
In diesem Staat
fetch(url, {
headers: new Headers({
Token: "abcd"
})
})
Wenn Sie ausführen ...
Access to fetch at 'http://localhost:8000/pilot' from origin 'null' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
** Ein Fehler wird auftreten. ** **.
Um zu verstehen, warum du süchtig bist
Es ist notwendig, die drei Punkte von zu verstehen. Ich werde in der Reihenfolge erklären.
Unabhängig davon, ob Sie Cookies oder Token verwenden, müssen Sie diese bei der Authentifizierung in den Anforderungsheader einfügen und vom Front-End zum Back-End übergeben. Wenn Sie daher den im Beispiel verwendeten "authHandler" erneut in etwas Realistischeres implementieren,
func authHandler(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
token := r.Header.Get("Token")
if token == "" {
...
}
...
h.ServeHTTP(w, r)
})
}
Es wird so etwas sein. Wichtig hierbei ist, dass Sie einen neuen ** Headernamen hinzufügen müssen, der ihn als Cookie oder Token ** identifiziert.
Tatsächlich hat CORS eine Einschränkung, und Sie können eine "einfache Anforderung" nur dann stellen, wenn die Werte, die in der Methode und im Header festgelegt werden können, die folgenden Bedingungen erfüllen. Hier ist eine einfache Anfrage eine allgemeine Anfrage.
method : GET, POST, HEAD header : Accept, Accept-Language, Content-Language, Content-Type(application/x-www-form-urlencoded, multipart/form-data, text/plain), DPR, Downlink, Save-Data, Viewport-Width, Width
Wenn Sie im ** -Header eigene Werte wie "Cookie" oder "Token" festlegen, können Sie daher keine einfache Anfrage stellen **. In diesem Fall stellen Sie im Voraus eine Anfrage mit dem Namen ** Preflight Request **. Weitere Informationen finden Sie unter MDN. Wenn Sie nur die erforderlichen Informationen schreiben, wird die Anforderung als Preflight-Anforderung mit der Methode "OPTIONS" gesendet. Nur wenn eine normale Antwort auf diese Preflight-Anforderung zurückgegeben wird, wird ein Wert wie "Token" in den Header eingefügt und eine "GET" - oder "POST" -Anforderung gesendet. Daher wird bei Verwendung von "Abrufen" die Anforderung zweimal hinter den Kulissen gesendet.
Zusammenfassend wird eine Preflight-Anfrage gesendet, wenn Sie Ihren eigenen Header-Wert verwenden. Hier werde ich den Flow vor und nach dem Ändern erneut veröffentlichen, damit mehrere Middleware angewendet werden kann.
Bisherige: request -> CORS -> logging -> routing -> pilotFunc or angelFunc
Rückseite: request -> routing -> CORS -> logging (-> auth) -> pilotFunc or angelFunc
Betrachten Sie die CORS-Middleware Handler
.
func (c *Cors) Handler(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method == http.MethodOptions && r.Header.Get("Access-Control-Request-Method") != "" {
...
w.WriteHeader(http.StatusNoContent)
} else {
...
h.ServeHTTP(w, r)
}
})
}
Der Prozess ist also verzweigt, je nachdem, ob es sich um die Options-Methode handelt oder nicht, und die Preflight-Anforderung wird entsprechend behandelt. Schauen Sie sich als Nächstes ServeHTTP
von mux.Router
an.
func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
...
if r.Match(req, &match) {
handler = match.Handler
...
}
if handler == nil && match.MatchErr == ErrMethodMismatch {
handler = methodNotAllowedHandler()
}
if handler == nil {
handler = http.NotFoundHandler()
}
handler.ServeHTTP(w, req)
}
Es sucht nach einem "Handler", der dem Wert von "url" in der Anforderung entspricht, und wenn nicht, verzweigt es sich je nachdem, ob die Methode fehlerhaft ist oder das Routing an erster Stelle steht, und behandelt den Fehler. ..
Daher hat sich die Verarbeitung für Preflight-Anforderungen vor und nach dem Ändern, um mehrere Middleware anwenden zu können, wie folgt geändert.
Bisherige: preflight request -> CORS check -> 204 No content
Rückseite: preflight request -> routing check -> 405 Method Not Allowed
Aus diesem Grund tritt der CORS-Fehler auf.
Sobald Sie dies wissen, ist es einfach, damit umzugehen. Ist es zum Beispiel am einfachsten, "OPTINOS" hinzuzufügen, wenn Sie "mux.Router" routen? Entschuldigung für das spätere, aber in rs / cors müssen Sie beim Hinzufügen Ihres eigenen Headers angeben, welche Art von Header zulässig ist. Siehe READ ME für Details. Basierend darauf wird die Implementierung wie folgt sein.
func main() {
c := cors.New(cors.Options{
AllowedOrigins: []string{"*"},
AllowedMethods: []string{
http.MethodHead,
http.MethodGet,
http.MethodPost,
},
AllowedHeaders: []string{"*"},
AllowCredentials: false,
})
logChain := alice.New(c.Handler, logHandler)
authChain := logChain.Append(authHandler)
r := mux.NewRouter()
r.Methods("GET", "OPTIONS").Path("/pilot").Handler(authChain.Then(funcHandler{pilotFunc}))
r.Methods("GET", "OPTIONS").Path("/angel").Handler(logChain.Then(funcHandler{angelFunc}))
http.ListenAndServe(":8000", r)
}
package main
import (
"encoding/json"
"log"
"net/http"
"github.com/gorilla/mux"
"github.com/justinas/alice"
"github.com/rs/cors"
)
type Character struct {
Name string `json:"name"`
}
type funcHandler struct {
handler func(w http.ResponseWriter, r *http.Request)
}
func (h funcHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
h.handler(w, r)
}
func pilotFunc(w http.ResponseWriter, r *http.Request) {
res, _ := json.Marshal(Character{"Shinji"})
w.WriteHeader(http.StatusOK)
w.Write(res)
}
func angelFunc(w http.ResponseWriter, r *http.Request) {
res, _ := json.Marshal(Character{"Adam"})
w.WriteHeader(http.StatusOK)
w.Write(res)
}
func logHandler(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
log.Printf("Method: %v; URL: %v; Protocol: %v", r.Method, r.URL, r.Proto)
h.ServeHTTP(w, r)
})
}
func authHandler(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
token := r.Header.Get("Token")
if token == "" {
w.WriteHeader(http.StatusUnauthorized)
return
}
h.ServeHTTP(w, r)
})
}
func main() {
c := cors.New(cors.Options{
AllowedOrigins: []string{"*"},
AllowedMethods: []string{
http.MethodHead,
http.MethodGet,
http.MethodPost,
},
AllowedHeaders: []string{"*"},
AllowCredentials: false,
})
logChain := alice.New(c.Handler, logHandler)
authChain := logChain.Append(authHandler)
r := mux.NewRouter()
r.Methods("GET", "OPTIONS").Path("/pilot").Handler(authChain.Then(funcHandler{pilotFunc}))
r.Methods("GET", "OPTIONS").Path("/angel").Handler(logChain.Then(funcHandler{angelFunc}))
http.ListenAndServe(":8000", r)
}
Alternativ können Sie "PathPrefix" verwenden, um alle "OPTIONEN" zu verarbeiten. (Ich weiß nicht, ob diese Methode gut ist, tut mir leid.)
func main() {
c := cors.New(cors.Options{
AllowedOrigins: []string{"*"},
AllowedMethods: []string{
http.MethodHead,
http.MethodGet,
http.MethodPost,
},
AllowedHeaders: []string{"*"},
AllowCredentials: false,
})
logChain := alice.New(c.Handler, logHandler)
authChain := logChain.Append(authHandler)
r := mux.NewRouter()
r.Methods("OPTIONS").PathPrefix("/").HandlerFunc(c.HandlerFunc)
r.Methods("GET").Path("/pilot").Handler(authChain.Then(funcHandler{pilotFunc}))
r.Methods("GET").Path("/angel").Handler(logChain.Then(funcHandler{angelFunc}))
http.ListenAndServe(":8000", r)
}
Übrigens, wie der Name schon sagt, fügt "Pathprefix" der URL ein gemeinsames Präfix hinzu. Zum Beispiel
r.PathPrefix("/products/")
Wenn diese Option aktiviert ist, gelten Anforderungen wie "http: // localhost: 8000 / products / hoge" und "http: // localhost: 8000 / products / fuga".
Wenn Sie CORS unterstützen möchten, stellen Sie sicher, dass Sie "OPTIONEN" unterstützen.
Vielen Dank für das Lesen des Langtextes. Wenn Sie es verstehen, scheint es eine einfache Sache zu sein, aber es gibt noch etwas zu tun. Eigentlich habe ich es nicht von Grund auf neu geschrieben, sondern geändert, was andere Leute geschrieben haben, und ich war dabei süchtig danach. Der von anderen Personen geschriebene Code lautet
func main() {
c := cors.New(cors.Options{
AllowedOrigins: []string{"*"},
AllowedMethods: []string{
http.MethodHead,
http.MethodGet,
http.MethodPost,
},
AllowedHeaders: []string{"*"},
AllowCredentials: false,
})
logChain := alice.New(c.Handler, logHandler)
authChain := logChain.Append(authHandler)
r := mux.NewRouter()
r.Methods("GET").Path("/pilot").Handler(authChain.Then(funcHandler{pilotFunc}))
r.Methods("GET").Path("/angel").Handler(logChain.Then(funcHandler{angelFunc}))
r.PathPrefix("").Handler(logChain.Then(http.StripPrefix("/img", http.FileServer(http.Dir("./img"))))) //Da war das.
http.ListenAndServe(":8000", r)
}
Es war so. Um das Bild zurückzugeben, heißt es "r.PathPrefix (" "). Handler (logChain.Then (http.StripPrefix (" / img ", http.FileServer (http.Dir (" ./ img ")))) Da war etwas. Ich hatte jedoch keine Möglichkeit, das Bild auf meinem Server zurückzugeben, daher habe ich diese Zeile gelöscht. Dann trat plötzlich ein Fehler in CORS auf und es war Panik. Außerdem führte das Verschieben dieser Zeile an den Anfang zu einem Fehler. Es war jedoch schwierig, die Fehlerursache zu identifizieren.
Ich wusste zum Zeitpunkt des Schreibens dieses Artikels
CORS kann mit verschiedenen Fehlern fehlschlagen. Aus Sicherheitsgründen wird jedoch festgelegt, dass die Fehler in JavaScript nicht bekannt sind. Der Code sagt Ihnen nur, dass ein Fehler aufgetreten ist. Die einzige Möglichkeit, genau zu wissen, was schief gelaufen ist, besteht darin, die Details in der Browserkonsole zu überprüfen.
... anscheinend ... Mit anderen Worten, egal welcher Fehler auftritt
Access to fetch at 'http://localhost:8000/pilot' from origin 'null' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
Wird angezeigt. Dies machte das Debuggen schwierig. Wenn ich jetzt darüber nachdenke, kann ich das Gefühl nicht leugnen, dass ich meine Zeit damit verschwendet habe zu denken, dass ich erraten könnte, welche Art von Fehler auftreten könnte, wenn ich die Arten von 4XX-Fehlern auf der Registerkarte Netzwerk mit Chrom betrachte. ist. Als ich das "Pathprefix (" ")" entfernte und es an den Anfang brachte, war der auf der Konsole angezeigte Fehlertext derselbe, aber der Status war 405 bzw. 404.
Warum wird "r.PathPrefix (" "). Handler (logChain.Then (http.StripPrefix (" / img ", http.FileServer (http.Dir (" ./ img ")))") hinzugefügt? Wenn ja, ist der Fehler nicht aufgetreten, die Anforderung "OPTIONEN http: // localhost: 8000 / pilot"
r.Methods("GET").Path("/pilot").Handler(authChain.Then(funcHandler{pilotFunc}))
Ich erhalte den Fehler "Methode nicht zulässig" für
r.PathPrefix("").Handler(logChain.Then(http.StripPrefix("/img", http.FileServer(http.Dir("./img")))))
Passt dagegen. Eigentlich wird der bei Gorilla / Mux registrierte Pfad in einen regulären Ausdruck konvertiert. Wenn Sie jedoch ein leeres Zeichen "" in "PathPrefix" registrieren, lautet der entsprechende reguläre Ausdruck "^". Daher wird "/ pilot" für das obige Routing nicht gefunden, und die Verarbeitung wird fortgesetzt.
Wenn die Methode "OPTIONS" lautet, gibt rs / cors sofort 204 No Content zurück, sodass das nachfolgende "http.StripPrefix" ("/ img", http.FileServer (http.Dir ("./ img")) Anfragen, die einen Fehler mit))) `verursachen, werden ebenfalls übergeben. Infolgedessen wurden durch das Routing, das Sie für die Rückgabe des Bilds eingerichtet haben, CORS-Fehler unbeabsichtigt vermieden.
Es gibt eine Idee, dass die Go-Sprache eine Kombination aus einfachen Sprachen ist, aber für Gollira / Mux, Rs / Cors und Justinas / Alice war diesmal die Anzahl der Dateien, die gelesen werden mussten, um das Verhalten zu verstehen, eins oder zwei. Es war einfach, den Prozess in der richtigen Reihenfolge zu lesen. Ich denke nicht, dass die Erklärungen in diesem Artikel alles vollständig erklären können. Wenn Sie also Fragen haben, schauen Sie sich bitte jede Implementierung selbst an.
Recommended Posts