在没有第三方路由库的情况下路由PUT请求

时间:2015-06-02 20:00:17

标签: go

在Blake Mizerany的Golang演讲的this Youtube视频(大约15:29)中,他谈到了如何在不使用第三方软件包的情况下构建路由器,详细介绍了如何构建路由有一个可变组件,例如id。这是他使用的处理程序,第一行显示如何获取路径的变量组件(即键)

func productHandler(w http.ResponseWriter, r *http.Request){
    key := r.URL.Path[len("/products/":]
    switch r.Method{
    case "GET":
      //do stuff
    case "POST"
      //do stuff
    default:
       http.Error(w, "method not allowed", 405)
    }
}

虽然他的实际路线是什么样的,但从他的演讲中并不清楚。

我正在尝试构建一个处理带有id的put请求的路由。当我单击页面上的元素时,它会向此路径发送一个put请求

http://localhost:8080/products/1433255183951

我有这样的路线

   http.HandleFunc("/products/{id}", doSomethingWithProduct){

   }

当然还有func

func doSomethingWithProduct(res http.ResponseWriter, req *http.Request{
     key := req.URL.Path[len("/products/"):]

     log.Println(key, "is this logging?? nope")

}

问题。即使我设置了这个路由,还有处理程序,当我单击该元素时,我找不到404,并且没有迹象表明我的函数被调用(即它没有记录)

问题:如何创建处理PUT请求的自定义路由/功能

http://localhost:8080/products/1433255183951

3 个答案:

答案 0 :(得分:3)

HandleFunc不知道如何处理{id}。给它一个可以匹配的特定路径:

http.HandleFunc("/products/", doSomethingWithProduct)

答案 1 :(得分:3)

http.HandleFunc不会像您尝试使用{id}那样处理“捕获群组”。

http.HandleFunc("/products/", handler)将匹配以此模式开头的所有路由。你必须自己解析剩下的部分。

请参阅ServeMux

  

ServeMux是一个HTTP请求多路复用器。它将每个传入请求的URL与已注册模式的列表进行匹配,并调用与该URL最匹配的模式的处理程序。

     

模式名称是固定的,有根的路径,如“/favicon.ico”,或有根的子树,如“/ images /”(请注意尾部斜杠)。较长的模式优先于较短的模式,因此如果存在为“/ images /”和“/ images / thumbnails /”注册的处理程序,则后面的处理程序将被调用以“/ images / thumbnails /”开头的路径和前者将收到“/ images /”子树中任何其他路径的请求。

     

请注意,由于以斜杠结尾的模式命名为带根子树,因此模式“/”匹配所有与其他已注册模式不匹配的路径,而不仅仅是带有Path ==“/".

的URL      

模式可以选择以主机名开头,仅限制与该主机上的URL匹配。特定于主机的模式优先于一般模式,因此处理程序可以注册两个模式“/ codesearch”和“codesearch.google.com/”,而不会接管“http://www.google.com/”的请求。

     

ServeMux还负责清理URL请求路径,重定向包含的任何请求。或..元素到等效的.-和..-免费URL。

答案 2 :(得分:3)

内置的HTTP路由器不像绑定参数那样做任何事情;但是,您可以指定整个前缀以与处理程序关联。请参阅http.ServeMux的文档。

尝试这样的事情:

func main() {
  productsPrefix := "/products/"
  http.HandleFunc(productsPrefix, func(w http.ResponseWriter, r *http.Request) {
    if (r.Method == "PUT") && (strings.Index(r.URL.Path, productsPrefix) == 0) {
      productId := r.URL.Path[len(productsPrefix):]
      fmt.Printf("OK: %s %s productId=%s\n", r.Method, r.URL.Path, productId)
    }
  })

  log.Print("Listening on localhost:8080")
  log.Fatal(http.ListenAndServe(":8080", nil))
}

例如:

$ curl -XPUT http://localhost:8080/products/1234
# => OK: PUT /products/1234 productId=1234