Go语言 使用POST和不同的查询向GET添加相同的端点会导致错误消息不一致

tzdcorbm  于 2022-12-16  发布在  Go
关注(0)|答案(1)|浏览(134)

当使用不同的方法添加相同的路由时,每个方法查询的get调用的响应是不同的,但是由于另一个方法是POST,它应该不受影响。
与POST:Playground:https://go.dev/play/p/xzoAkpEhGgy

// You can edit this code!
// Click here and start typing.
package main

import (
"encoding/json"
"fmt"
"net/http"
"net/http/httptest"
"time"

    "github.com/gorilla/mux"

)

func main() {

    r := mux.NewRouter()
    
    r.HandleFunc("/api/v2", func(w http.ResponseWriter, r *http.Request) {
        // an example API handler
        fmt.Fprintf(w, "You made a POST request")
        json.NewEncoder(w).Encode(map[string]bool{"ok": true})
    }).Methods("POST")
    
    r.HandleFunc("/api/v2", func(w http.ResponseWriter, r *http.Request) {
        // an example API handler
        fmt.Fprintf(w, "You made a GET request")
        json.NewEncoder(w).Encode(map[string]bool{"ok": true})
    }).
        Queries("from", "{from:[0-9]+}",
            "to", "{to:[0-9]+}").Methods("GET")
    
    
    srv := &http.Server{
        Handler: r,
        Addr:    "127.0.0.1:8000",
        // Good practice: enforce timeouts for servers you create!
        WriteTimeout: 15 * time.Second,
        ReadTimeout:  15 * time.Second,
    }
    go srv.ListenAndServe()
    
    
    req2 := httptest.NewRequest("GET", "/api/v2?from=3&to=-5", nil)
    out2 := httptest.NewRecorder()
    
    r.ServeHTTP(out2, req2)
    
    fmt.Println(out2.Code)
    fmt.Println(out2)

}

预期404,得到405
移除POSTPlayground时:https://go.dev/play/p/EXiF00_WrFW

// You can edit this code!
// Click here and start typing.
package main

import (
    "encoding/json"
    "fmt"
    "net/http"
    "net/http/httptest"
    "time"

    "github.com/gorilla/mux"
)

func main() {

    r := mux.NewRouter()

    r.HandleFunc("/api/v2", func(w http.ResponseWriter, r *http.Request) {
        // an example API handler
        fmt.Fprintf(w, "You made a GET request")
        json.NewEncoder(w).Encode(map[string]bool{"ok": true})
    }).
        Queries("from", "{from:[0-9]+}",
            "to", "{to:[0-9]+}").Methods("GET")

    srv := &http.Server{
        Handler: r,
        Addr:    "127.0.0.1:8000",
        // Good practice: enforce timeouts for servers you create!
        WriteTimeout: 15 * time.Second,
        ReadTimeout:  15 * time.Second,
    }
    go srv.ListenAndServe()

    req2 := httptest.NewRequest("GET", "/api/v2?from=3&to=-5", nil)
    out2 := httptest.NewRecorder()

    r.ServeHTTP(out2, req2)

    fmt.Println(out2.Code)

}

结果404
对于GET请求,路由和结果应该一致。404-s
我很好奇以前有没有人见过这个问题?

eqqqjvef

eqqqjvef1#

路由器将尝试根据路径和查询参数查找匹配项。由于查询字符串参数与要求不匹配,因此GET路由不匹配。
但是路径与POST路由匹配,因为该路由不关心那些查询参数。然后检查请求方法,它与路由不匹配,因此返回405 Method Not Allowed(该路由有一个处理程序,但用于不同的方法)。
您可以通过为同一路径添加捕获所有GET处理程序来获得所需的行为:

// You can edit this code!
// Click here and start typing.
package main

import (
    "encoding/json"
    "fmt"
    "net/http"
    "net/http/httptest"
    "time"

    "github.com/gorilla/mux"
)

func main() {

    r := mux.NewRouter()

    r.HandleFunc("/api/v2", func(w http.ResponseWriter, r *http.Request) {
        // an example API handler
        fmt.Fprintf(w, "You made a POST request")
        json.NewEncoder(w).Encode(map[string]bool{"ok": true})
    }).Methods("POST")

    r.HandleFunc("/api/v2", func(w http.ResponseWriter, r *http.Request) {
        // an example API handler
        fmt.Fprintf(w, "You made a GET request")
        json.NewEncoder(w).Encode(map[string]bool{"ok": true})
    }).
        Queries("from", "{from:[0-9]+}",
            "to", "{to:[0-9]+}").
        Methods("GET")
    r.HandleFunc("/api/v2", func(w http.ResponseWriter, r *http.Request) {
        http.Error(w, "", http.StatusNotFound)
    }).Methods("GET")

    srv := &http.Server{
        Handler: r,
        Addr:    "127.0.0.1:8000",
        // Good practice: enforce timeouts for servers you create!
        WriteTimeout: 15 * time.Second,
        ReadTimeout:  15 * time.Second,
    }
    go srv.ListenAndServe()

    req2 := httptest.NewRequest("GET", "/api/v2?from=3&to=-5", nil)
    out2 := httptest.NewRecorder()

    r.ServeHTTP(out2, req2)

    fmt.Println(out2.Code)

}

相关问题