gorilla / mux, rs / cors, [justinas / alice](https: // github. Je vais vous montrer comment faire un serveur en combinant com / justinas / alice). En particulier, lorsque j'ai essayé de diviser le middleware à appliquer en fonction du chemin, j'étais accro à CORS, donc je vais me concentrer sur la partie liée à cela. Dans le code à publier, il s'agit essentiellement d'une manière d'écrire qui ignore les erreurs, veuillez donc réécrire comme il convient. Notez également que «...» dans le code signifie simplement une abréviation et n'a pas de signification grammaticale, alors soyez prudent lors de la copie.
tl;dr
Attention à la méthode ʻOPTIONS` de la demande de contrôle en amont.
Quelques exemples sont présentés, mais comme il s'agit du contenu de base tel que décrit dans chaque README, si vous le connaissez, veuillez passer à [Sujet de l'implémentation](# Sujet de l'implémentation).
gorilla/mux
Voici un exemple de serveur utilisant mux.
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 est*mux.Type de routeur
r.Methods("GET").Path("/pilot").HandlerFunc(pilotFunc) // r.aux itinéraires*mux.Ajouter une route.
r.Methods("GET").Path("/angel").HandlerFunc(angelFunc) // r.routes est[]*mux.Puisqu'il s'agit d'un type d'itinéraire, vous pouvez en ajouter de plus en plus.
http.ListenAndServe(":8000", r)
}
Avec cela, un petit serveur est terminé.
$ go run main.go
$ curl http://localhost:8000/pilot
{"name": "Shinji"}
Cependant, lorsque j'utilise fetch
depuis un navigateur, j'obtiens l'erreur suivante:
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
C'est là que rs / cors entre en jeu. Pour CORS, la page MDN est facile à comprendre. Afin de prendre en charge CORS, il est nécessaire de définir une valeur appropriée dans l'en-tête de réponse côté serveur. Rs / cors en est responsable. J'ai ajouté rs / cors à l'exemple précédent.
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) //Ajoutée.
http.ListenAndServe(":8000", c) //Changé de r à c.
}
Vous pouvez prendre en charge CORS simplement en ajoutant une ligne.
justinas/alice
De plus, justinas / alice est utile lorsque vous souhaitez ajouter un middleware qui affiche le contenu de la requête dans le journal à chaque fois, ou un middleware qui récupère la valeur de l'en-tête de la requête avant d'effectuer le traitement principal. (: //github.com/justinas/alice). Voici un exemple de création et d'ajout de middleware qui génère des informations de demande dans le journal.
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) //Ajoutée.
http.ListenAndServe(":8000", chain) //Changé de c en chaîne.
}
À propos, gorilla / mux, rs / cors, [justinas / alice](https: // Je republierai la combinaison de toutes les définitions de github.com/justinas/alice (packge, import, struct omises).
...
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)
}
Cependant, avec cette méthode, le middleware défini sera appliqué à toutes les requêtes.
Par exemple, / pilot
vérifie si vous êtes connecté et ne renvoie des données que si vous êtes connecté, mais / angel
ne peut pas répondre aux demandes qui renvoient des données même si vous n'êtes pas connecté. Avec Qiita, vous pouvez voir la page de l'article même si vous n'êtes pas connecté, mais imaginez une situation où vous ne pouvez pas voir le brouillon de Ma page à moins que vous ne soyez connecté.
Par conséquent, essayez ce qui suit. Comme je l'ai dit plus tôt, je suis accro au style d'écriture ci-dessous (rires).
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)
}
Maintenant, seulement quand fetch
est fait vers / pilot
, ʻAuthentication` est sortie vers la sortie standard. Il est maintenant possible de séparer le middleware à appliquer en fonction du chemin.
$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
Je vais laisser l'explication de pourquoi cela crée une dépendance et expliquer brièvement le mécanisme de réécriture de cette manière. Si vous voulez d'abord savoir pourquoi vous êtes accro, veuillez passer à [Raison de la dépendance](# Raison de la dépendance).
Commençons par vérifier ce que fait http.ListenAndServer
, mais [Go] Comment lire le package net / http et exécuter http.HandleFunc / items / 1d1c64d05f7e72e31a98) est assez détaillé, je vais donc le jeter ici. Il semble que les informations soient un peu anciennes et que le numéro de ligne écrit ne correspond pas au numéro de ligne réel, ou que le style d'écriture soit légèrement différent, mais je pense qu'il n'y a pas de problème de compréhension de base.
En conclusion, http.ListenAndServe
transmet la requête reçue à ServeHTTP
dans le deuxième argument (cette fois mux.Router
). Par conséquent, le deuxième argument doit implémenter «ServeHTTP». ServeHTTP
est implémenté dans mux.Router
, et dans le paquet http
,
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}
Toute variable de type http.Handler
peut être le deuxième argument de ListenAndServe
. Dans ce "ServeHTTP", appelez le "ServeHTTP" d'un autre "http.Hanlder", puis dans ce "ServeHTTP", appelez le "ServeHTTP" de l'autre "http.Hanlder", et ainsi de suite. En chaînant .Handler`, vous pouvez traiter les demandes dans l'ordre.
En d'autres termes, vous pouvez enchaîner des gestionnaires en utilisant une fonction qui prend http.Handler
comme argument et renvoie un type http.Handler
, ** c'est-à-dire un middleware **. À titre d'exemple, considérons la chaîne de «logHandler» et «authHandler».
chain := logHandler(authHandler(router))
Une telle chaîne peut être envisagée. Cependant, avec cette méthode, il devient plus difficile à comprendre à mesure que le nombre de middleware augmente, donc en utilisant alice,
chain := alice.New(logHandler, authHandler).Then(router)
Est écrit brièvement.
Ici, comparons avant et après la réécriture afin que le middleware appliqué puisse être modifié en fonction du chemin.
//Changer avant
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)
}
//Après le changement
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)
}
Par conséquent, le flux que la demande avant et après le changement suit est
précédent: request -> CORS -> logging -> routing -> pilotFunc or angelFunc
arrière: request -> routing -> CORS -> logging (-> auth) -> pilotFunc or angelFunc
Vous pouvez voir que l'ordre de routage a changé. C'est l'une des raisons pour lesquelles j'en suis accro.
Ensuite, j'expliquerai pourquoi je suis accro à CORS, qui est le sujet principal de cet article.
Tout d'abord, je décrirai une implémentation du mécanisme d'authentification (les détails seront décrits plus loin) qui est un peu plus proche de l'actuel.
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)
}
Dans cet état
fetch(url, {
headers: new Headers({
Token: "abcd"
})
})
Lorsque vous exécutez ...
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.
** Une erreur se produira. ** **
Pour comprendre pourquoi tu es accro
Il est nécessaire de comprendre les trois points de. Je vais expliquer dans l'ordre.
Lors de l'authentification, que vous utilisiez des cookies ou des jetons, vous devez les mettre dans l'en-tête de la demande et les transmettre du front-end au back-end. Par conséquent, si vous réimplémentez ʻauthHandler` utilisé dans l'exemple en quelque chose de plus réaliste,
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)
})
}
Ce sera quelque chose comme ça. L'important ici est que vous devez ajouter un nouveau ** nom d'en-tête qui l'identifie en tant que cookie ou Token **.
En fait, CORS a une limitation, et vous ne pouvez faire une "demande simple" que lorsque les valeurs qui peuvent être définies dans la méthode et l'en-tête remplissent les conditions suivantes. Ici, une simple demande est une demande générale.
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
Par conséquent, si vous définissez vos propres valeurs telles que «Cookie» ou «Token» dans l'en-tête **, vous ne pouvez pas faire une simple requête **. Dans ce cas, faites une demande appelée ** Demande de contrôle en amont ** à l'avance. Voir MDN pour plus d'informations. Si vous n'écrivez que les informations nécessaires, la requête sera envoyée en tant que requête de contrôle en amont avec la méthode ʻOPTIONS`. Seulement lorsqu'une réponse normale est renvoyée à cette demande de contrôle en amont, une valeur telle que «Token» est placée dans l'en-tête et une demande «GET» ou «POST» est envoyée. Par conséquent, lors de l'utilisation de «fetch», la requête est envoyée deux fois dans les coulisses.
En résumé, si vous utilisez votre propre valeur d'en-tête, une demande de contrôle en amont sera envoyée. Ici, je republierai le flux avant et après le changement afin que plusieurs intergiciels puissent être appliqués.
précédent: request -> CORS -> logging -> routing -> pilotFunc or angelFunc
arrière: request -> routing -> CORS -> logging (-> auth) -> pilotFunc or angelFunc
En regardant le middleware CORS 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)
}
})
}
Ainsi, le processus est ramifié selon qu'il s'agit de la méthode Options ou non, et la demande de contrôle en amont est traitée de manière appropriée. Ensuite, si vous regardez ServeHTTP
de mux.Router
,
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)
}
Il recherche un handler
qui correspond à la valeur de ʻurl` dans la requête, et si ce n'est pas le cas, il se branche selon que la méthode est en erreur ou que le routage est en premier lieu, et gère l'erreur. ..
Par conséquent, avant et après le changement pour appliquer plusieurs intergiciels, le traitement de la demande de contrôle en amont a changé comme suit.
précédent: preflight request -> CORS check -> 204 No content
arrière: preflight request -> routing check -> 405 Method Not Allowed
C'est pourquoi l'erreur CORS se produit.
Une fois que vous savez cela, c'est facile à gérer. Par exemple, est-il plus simple d'ajouter ʻOPTINOSlors du routage de
mux.Router`? Désolé pour le plus tard, mais dans rs / cors, lors de l'ajout de votre propre en-tête, vous devez spécifier le type d'en-tête autorisé. Voir LISEZ-MOI pour plus de détails. Sur cette base, la mise en œuvre sera la suivante.
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)
}
Alternativement, vous pouvez utiliser «PathPrefix» pour gérer toutes les «OPTIONS». (Je ne sais pas si cette méthode est bonne, je suis désolé.)
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)
}
En passant, comme son nom l'indique, Pathprefix
ajoute un préfixe commun à url. Par exemple
r.PathPrefix("/products/")
Si défini sur, les requêtes telles que «http: // localhost: 8000 / products / hoge» et «http: // localhost: 8000 / products / fuga» seront applicables.
Si vous souhaitez prendre en charge CORS, assurez-vous de prendre en charge ʻOPTIONS`.
Merci d'avoir lu le long texte. Quand vous le comprenez, il semble que ce soit une chose simple, mais il y a encore une chose à faire. En fait, je ne l'ai pas écrit à partir de zéro, mais j'ai changé ce que les autres ont écrit, et j'y ai été accro dans le processus. Le code écrit par d'autres personnes est
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"))))) //Il y avait ça.
http.ListenAndServe(":8000", r)
}
C'était comme ça. Pour renvoyer l'image, elle s'appelle r.PathPrefix (" "). Handler (logChain.Then (http.StripPrefix (" / img ", http.FileServer (http.Dir (" ./ img "))))))
Il y avait quelque chose. Cependant, je n'ai pas eu la chance de renvoyer l'image sur mon serveur, j'ai donc supprimé cette ligne. Puis, soudainement, une erreur a commencé à se produire dans CORS et c'était la panique. De plus, déplacer cette ligne au début a entraîné une erreur. Cependant, il était difficile d'identifier la cause de l'erreur.
Je savais au moment de la rédaction de cet article
CORS peut échouer avec diverses erreurs, mais pour des raisons de sécurité, il est stipulé que les erreurs ne peuvent pas être connues à partir de JavaScript. Le code vous indique seulement qu'une erreur s'est produite. La seule façon de savoir exactement ce qui ne va pas est de regarder les détails dans la console du navigateur.
... Apparemment ... En d'autres termes, quelle que soit l'erreur qui se produit
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.
Est affiché. Cela a rendu le débogage difficile. Quand j'y pense maintenant, je ne peux pas nier le sentiment que j'ai perdu mon temps à penser que je pourrais deviner quel type d'erreur pourrait se produire en regardant les types d'erreurs 4XX de l'onglet Réseau avec chrome. est. En fait, lorsque j'ai supprimé le préfixe `Pathprefix (" ") et que je l'ai amené au début, le texte d'erreur affiché sur la console était le même, mais l'état était respectivement 405 et 404.
Alors pourquoi r.PathPrefix (" "). Handler (logChain.Then (http.StripPrefix (" / img ", http.FileServer (http.Dir (" ./ img "))))) ʻadded Si tel est le cas, l'erreur ne s'est pas produite. La requête ʻOPTIONS http: // localhost: 8000 / pilot
r.Methods("GET").Path("/pilot").Handler(authChain.Then(funcHandler{pilotFunc}))
J'obtiens une erreur Méthode non autorisée pour
r.PathPrefix("").Handler(logChain.Then(http.StripPrefix("/img", http.FileServer(http.Dir("./img")))))
S'adaptera contre. En fait, le chemin enregistré avec gorilla / mux est converti en une expression régulière, mais si vous enregistrez un caractère vide "" dans PathPrefix
, l'expression régulière correspondante sera" ^ "
. Par conséquent, «/ pilot» ne devient pas introuvable pour le routage ci-dessus, et le traitement se poursuit.
De plus, si la méthode est ʻOPTIONS, rs / cors renvoie immédiatement 204 No Content, donc le suivant
http.StripPrefix (" / img ", http.FileServer (http.Dir (" ./ img ")) Les requêtes qui provoquent une erreur avec))) `seront également transmises. Par conséquent, le routage que vous configurez pour renvoyer les images évite involontairement les erreurs CORS.
Il y a une idée que le langage Go est une combinaison de langages simples, mais pour gollira / mux, rs / cors et justinas / alice cette fois, le nombre de fichiers à lire pour comprendre le comportement était d'un ou deux. , Il était facile de lire le processus dans l'ordre. Je ne pense pas que les explications de cet article peuvent tout expliquer complètement, donc si vous avez des questions, veuillez jeter un œil à chaque implémentation par vous-même.
Recommended Posts