在没有第三方路由库的情况下,如何路由一个PUT请求?

huangapple go评论86阅读模式
英文:

route a PUT request without a third party routing library

问题

在这个YouTube视频(大约在15:29处)中,Blake Mizerany进行了一次关于Golang的讲座,他讲解了如何构建一个没有使用第三方包的路由器,并详细介绍了如何构建具有变量组件(例如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 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

英文:

In this Youtube video (at around 15:29) of a Golang talk by Blake Mizerany, he talks about how to build a router without using a third party package, covering in detail how to construct a route that has a variable component, such as an id. This is the handler that he uses, with the first line showing how to get the variable component of the route (i.e. the key)

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)
    }
}

It's not clear from his presentation though what his actual route looks like.

I'm trying to build a route that handles a put request with an id. When I click an element on my page, it sends a put request to this route

http://localhost:8080/products/1433255183951

I have a route like this

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

   }

and of course have the func

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

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

}

Problem. Even though I have that route set up, and the handler, when I click the element I got a 404 not found, and there's no indication that my function was called (i.e. it's not logging)

Question: How do I create a custom route/func that handles a PUT request to

http://localhost:8080/products/1433255183951

答案1

得分: 3

HandleFunc不知道如何处理{id}。给它一个具体的路径以供匹配:

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

HandleFunc doesn't know what to do with {id}. Give it a specific path it can match:

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

答案2

得分: 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。

英文:

http.HandleFunc does not handle the "capture groups" like you're trying to do with {id}.

http.HandleFunc("/products/", handler) will match all routes that begin with this pattern. You have to parse the rest of it yourself.

See ServeMux.

>ServeMux is an HTTP request multiplexer. It matches the URL of each incoming request against a list of registered patterns and calls the handler for the pattern that most closely matches the URL.

> Patterns name fixed, rooted paths, like "/favicon.ico", or rooted subtrees, like "/images/" (note the trailing slash). Longer patterns take precedence over shorter ones, so that if there are handlers registered for both "/images/" and "/images/thumbnails/", the latter handler will be called for paths beginning "/images/thumbnails/" and the former will receive requests for any other paths in the "/images/" subtree.

> Note that since a pattern ending in a slash names a rooted subtree, the pattern "/" matches all paths not matched by other registered patterns, not just the URL with Path == "/".

> Patterns may optionally begin with a host name, restricting matches to URLs on that host only. Host-specific patterns take precedence over general patterns, so that a handler might register for the two patterns "/codesearch" and "codesearch.google.com/" without also taking over requests for "http://www.google.com/".

> ServeMux also takes care of sanitizing the URL request path, redirecting any request containing . or .. elements to an equivalent .- and ..-free URL.

答案3

得分: 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
英文:

The builtin HTTP router doesn't do anything fancy like binding parameters; however, you can specify entire prefixes to associate with a handler. See the documentation for http.ServeMux.

Try something like this:

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))
}

For example:

<!-- language: lang-none -->

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

huangapple
  • 本文由 发表于 2015年6月3日 04:00:17
  • 转载请务必保留本文链接:https://go.coder-hub.com/30605500.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定