julienschmidt / httprouter Goto Github PK
View Code? Open in Web Editor NEWA high performance HTTP request router that scales well
Home Page: https://pkg.go.dev/github.com/julienschmidt/httprouter
License: BSD 3-Clause "New" or "Revised" License
A high performance HTTP request router that scales well
Home Page: https://pkg.go.dev/github.com/julienschmidt/httprouter
License: BSD 3-Clause "New" or "Revised" License
It seems like it do not support the extensive domain name analysis.
Do you have a plan?
Trying to setup routes like /storage/:name.js
makes httprouter think parameter name is :name.js
instead of (desired) :name
. Is there a way around it or is that by design?
I'm having difficulty implementing a wildcard route that handles all paths except the assets directory.
r.Static("/public" , "./public")
r.GET("/*_", func(c *gin.Context) {...})
I'm getting 'panic: conflict with wildcard route'
How can this be handled with httprouter?
I apologize if I am missing something obvious; How do I define a route for OPTIONS requests?
Any chance of adding support for http HEAD requests?
Panic:
http: panic serving 127.0.0.1:33049: runtime error: index out of range
/home/me/goworkspace/src/github.com/julienschmidt/httprouter/router.go:287 +0x4a0
Offending line:
if path[len(path)-1] == '/' {
Link to source: https://github.com/julienschmidt/httprouter/blob/.../router.go#L287
Program to run:
package main
import (
"fmt"
"net/http"
"github.com/julienschmidt/httprouter"
)
func main() {
r := httprouter.New()
r.HandlerFunc("GET", "/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "Hello from")
})
fmt.Println(http.ListenAndServe(":8080", r))
}
Command to run, to cause panic:
echo -e 'GET http://www.example.com HTTP/1.1\r\n' | ncat localhost 8080
Reasoning:
net/url.URL.Path
to be empty (as per RFC 3986).In
Line 287 in 7deadb6
if path[len(path)-1] == '/' {
Variably, "/" and '/' are used, seemingly interchangeably. The former represents a string, the latter represents a rune literal. Is the variable representation intentional? It seems like it could lead to bugs down the line.
Just a small issue here. In README.md under Where can I find Middleware X? there is a statement in the second paragraph which states:
Alternatively, you could try a framework building upon HttpRouter.
However the link returns a 404 page, and should most likely refer to the Web Frameworks building upon HttpRouter section at the bottom of README.md instead.
Julien,
Can you give me a hint on what me be changed so that the route parameters are enclosed in {} and question marks can be used to make it optional just like in Laravel.
http://laravel.com/docs/4.2/routing#route-parameters
Route::get('user/{id}', function($id)
{
return 'User '.$id;
});
Optional Route Parameters
Route::get('user/{name?}', function($name = null)
{
return $name;
});
Optional Route Parameters With Defaults
Route::get('user/{name?}', function($name = 'John')
{
return $name;
});
Regular Expression Route Constraints
Route::get('user/{name}', function($name)
{
//
})
->where('name', '[A-Za-z]+');
Route::get('user/{id}', function($id)
{
//
})
->where('id', '[0-9]+');
Hi, I m serving a single page application from /
http.Handle("/", http.FileServer(http.Dir("./web_root")))
http.HandleFunc("/order_create", handlerOrderCreate)
http.HandleFunc("/order_show", handlerOrderShow)
--> works fine
router.ServeFiles("/*filepath", http.Dir("./web_root"))
router.GET( "/orders/:id", handlerOrderShow)
router.POST("/orders", handlerOrderCreate)
--> panic: conflict with wildcard route
goroutine 16 [running]:
runtime.panic(0x293240, 0xc208000980)
/usr/local/go/src/pkg/runtime/panic.c:279 +0xf5
github.com/julienschmidt/httprouter.(*node).addRoute(0xc2080042a0, 0x392f70, 0xb, 0x433330)
/Users/sallas/go/src/github.com/julienschmidt/httprouter/tree.go:141 +0x594
What could I do to make it work in /?
Hello,
I am porting an application where all traffic gets sent to the same index.html, regardless of path except the API endpoint. AngularJS is responsible for building the page. Go will work as the API that will tell Angular how the page is served.
Essentially I need all traffic aside from anything under the 'foo.com/mongolar' (this is configurable) to be routed to one index.html.
I am having problem with the wildcard route. Is this doable with your router?
I am also serving some js and css as static files from their own folders.
I tried the following, but it didn't work
router.ServeFiles("/*filepath", http.Dir("public/"))
// or
http.Handle("/", http.FileServer(http.Dir("public/")))
As reported by @ydnar in #51, the 405 Support introduced in #51 breaks wildcard routes:
This completely breaks wildcard routes for alternate methods, for example:
r.Handle("GET", "/v1/search", search)
r.Handle("OPTIONS", "/*path", handler)
GET requests for /v1/search will always return a 405 with this change.
When trying to add simple routes that should not overlap, I get wildcard route conflicts.
Simple crafted example:
package main
import (
"fmt"
"net/http"
"github.com/julienschmidt/httprouter"
)
func Index(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "Welcome!\n")
}
func main() {
router := httprouter.New()
router.Handler("HEAD", "/:some/:thing", http.HandlerFunc(Index))
router.Handler("GET", "/:some/:thing", http.HandlerFunc(Index))
router.Handler("GET", "/otherthing", http.HandlerFunc(Index))
http.Handle("/", router)
}
$ go run test.go
goroutine 1 [running]:
runtime.panic(0x1afa20, 0xc21000a600)
/go/1.2.2/libexec/src/pkg/runtime/panic.c:266 +0xb6
github.com/julienschmidt/httprouter.(*node).insertChild(0xc2100390c0, 0xc210000102, 0x254591, 0xc, 0xc21000a5f0)
/build/src/github.com/julienschmidt/httprouter/tree.go:201 +0x148
github.com/julienschmidt/httprouter.(*node).addRoute(0xc2100390c0, 0x254591, 0xc, 0xc21000a5f0)
/build/src/github.com/julienschmidt/httprouter/tree.go:172 +0x8d5
github.com/julienschmidt/httprouter.(*Router).Handle(0xc2100484a0, 0x247fe0, 0x3, 0x254590, 0xd, ...)
/build/src/github.com/julienschmidt/httprouter/router.go:205 +0x15a
github.com/julienschmidt/httprouter.(*Router).Handler(0xc2100484a0, 0x247fe0, 0x3, 0x254590, 0xd, ...)
/build/src/github.com/julienschmidt/httprouter/router.go:215 +0x9f
main.main()
/some/user/path/test.go:18 +0x16d
exit status 2
In the sample code the routes that appear to conflict are /:some/:thing
and /otherthing
. These should not really be conflicting though, as one requires two path components, and the other is a fixed route with no wildcards. Kind of odd. Is this a bug or intended behavior?
I am new to go. I copy your example from usage and build it. I got error.
c:\Apps\Google\Projects\myGoAppWebstorm\src>go build myGoAppWebstorm.go
myGoAppWebstorm.go:5:5: cannot find package "github.com/julienschmidt/httprouter
" in any of:
C:\Go\src\pkg\github.com\julienschmidt\httprouter (from $GOROOT)
C:\Apps\Google\Projects\src\github.com\julienschmidt\httprouter (from $G
OPATH)
What am I doing wrong?
Hello!
I would like know if is possible put a name to routes like as:
router := httprouter.New()
router.GET("/hello/:name", Hello).Name("hello")
....
routeHello := router.GetRoute("hello").Params("name", "Emilio")
If this is not possible, Do you plan add this feature?
P.D.: Very nice perfomance 👍
Best,
Emilio
Unless I'm missing something, currently the handle method (http://godoc.org/github.com/julienschmidt/httprouter#Router.Handle) can only handle a single HTTP method (e.g. GET, POST etc).
It would be great if we could do something like router.Handle("ALL", "/", myHandler)
and then have a switch
statement within myHandler
for each HTTP method
Hi!
Would be good idea add roles and permissions at routes? In this moment, i have a project, where i need put roles and permissions (like as rbac or acl). In beginning, i thought put this in each view where pointing every route, but, i think that it is better add roles and permissions necessary in each route, and do the checks of permissions in the wrapper httpHandler function.
I don't know if this affect to performance..
P.D.: sorry for my english.
I tried searching the documentation for an explaination on how to server static content from "/". In my application design all of the API uses /api/* all paths outside the api folder are considered static content.
Is there a current way of handling this in httprouter?
Not so much an issue, as much as a question.
Just wondering why Param
is a struct
instead of a map
.
Wouldn't it be more efficient to say if value, ok := ps["somekey"]; ok { foo(value) }
?
Since Param
is a struct
ByName(name string)
looks like it iterates through the array of Param
s until a string match its found. I totally get that ps[0]
is slightly more performant, but wouldn't a map be more useful for string matching? Maybe not?
Just curious what influenced the data structure choice for Param
! Im sure there is a good reason!
Thanks again for this router!!!
I am a little confused, how do you implement basic route of the form "/:title" without conflicting with "/"
When I use these 2 distinct routes, I get a panic. Seems to me like this is a bug? Am I missing something?
router.GET("/api/v1/:user_id/buoys/:id/show/", Hello)
router.GET("/api/v1/:user_id/buoys/:name/search/", Hello)
Sample program below:
package main
import (
"fmt"
"log"
"net/http"
"github.com/OutCast-IO/httprouter"
)
func Index(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
fmt.Fprint(w, "Welcome!\n")
}
func Hello(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
fmt.Fprintf(w, "hello")
}
func main() {
router := httprouter.New()
router.GET("/api/v1/:user_id/buoys/:id/show/", Hello)
router.GET("/api/v1/:user_id/buoys/:name/search/", Hello)
log.Fatal(http.ListenAndServe(":8080", router))
}
The following program panics with "slice bounds out of range" error. This
case should be caught and a more understandable message issued instead.
package main
import (
"github.com/julienschmidt/httprouter"
"net/http"
)
func main() {
r := httprouter.New()
r.Handle("GET", "/:foo:bar/oops", func(http.ResponseWriter, *http.Request, httprouter.Params) {})
}
The panic is as follows:
panic: runtime error: slice bounds out of range
goroutine 1 [running]:
github.com/julienschmidt/httprouter.(*node).insertChild(0xc20805c120, 0x1, 0x6bd190, 0xe, 0x72ea70)
/home/rog/src/go/src/github.com/julienschmidt/httprouter/tree.go:217 +0x57a
github.com/julienschmidt/httprouter.(*node).addRoute(0xc20805c060, 0x6bd190, 0xe, 0x72ea70)
/home/rog/src/go/src/github.com/julienschmidt/httprouter/tree.go:184 +0xac
github.com/julienschmidt/httprouter.(*Router).Handle(0xc208030f70, 0x6af1d0, 0x3, 0x6bd190, 0xe, 0x72ea70)
/home/rog/src/go/src/github.com/julienschmidt/httprouter/router.go:219 +0x1ae
main.main()
/home/rog/src/tst.go:10 +0x9a
Hi!
Thank you for your job! It's great!
Could you please approach me, how sub-domains could be supported?
Thanks
When a path matches but the method doesn't, I'd like to respond with a custom MethodNotAllowed handler. Is this something you'd consider for this library?
Say I made a blog app with httprouter
. It would be nice if my users could run it under an url-prefix like /blog
easily, without having to plug all the cords in the right places.
This is super easy to solve; my blogapp
package exports an httprouter.Router
-value with all its routes already configured correctly and the users just chain it to their router.
Something like this:
import "blogapp"
// ...
router.Chain("/blog", blogapp.Router)
After that line, any request that matches the prefix /blog
will be routed by blogapp.Router
.
Low complexity, great value.
I am not sure email for help is mentioned or there is a mailing list for this project.
How do parse query parameter? Like I have /hello?name=abhijit the for this pattern I should get "abhijit" when I read from ps.ByName("name"), however unable to read
I am running into sudden increase of connection timeouts after switching from gorilla/mux to httprouter.
My briefly skimming of the source code didn't reveal anything and it seemed unintuitive to me that changing routing package could lead to more timeouts.
Test client, written in node.js, makes 30 requests in parallel, 4000 in total.
Using gorilla/mux, there were zero ETIMEDOUT errors.
Using httprouter, client ran into ~10 ETIMEDOUT errors.
Are there any differences you are aware of in how your package handles connections vs how Gorilla does it?
hi,
Is there any way to remove a registered handler? for example:
router.Remove("GET", "/hello/:name")
Thanks.
Hi,
I am trying to use httprouter
for part of my routes. An example is
package main
import (
"fmt"
"log"
"net/http"
"github.com/julienschmidt/httprouter"
)
func Index(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
fmt.Fprint(w, "Welcome!\n")
}
func Hello(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
fmt.Fprintf(w, "hello, %s!\n", ps.ByName("name"))
}
func main() {
router := httprouter.New()
//router.GET("/", Index)
router.GET("/api/hello/:name", Hello)
http.Handle("/api/", router)
log.Fatal(http.ListenAndServe(":8080", nil))
}
this works, but crashes when given a url like
http://localhost:8080/api/world/abc
stack trace is
2014/06/11 09:30:09 http: panic serving [::1]:51474: runtime error: index out of range
goroutine 3 [running]:
net/http.func·009()
/Users/bsr/Work/ttt/repo/go/src/pkg/net/http/server.go:1093 +0xae
runtime.panic(0x2066c0, 0x497457)
/Users/bsr/Work/ttt/repo/go/src/pkg/runtime/panic.c:248 +0x106
github.com/julienschmidt/httprouter.(*node).getValue(0xc2100380c0, 0xc210048504, 0xe, 0x0, 0x0, ...)
/Users/bsr/Work/ttt/src/github.com/julienschmidt/httprouter/tree.go:409 +0x3f2
github.com/julienschmidt/httprouter.(*Router).ServeHTTP(0xc2100484a0, 0x584500, 0xc21000f460, 0xc2100581a0)
/Users/bsr/Work/ttt/src/github.com/julienschmidt/httprouter/router.go:266 +0xf9
net/http.(*ServeMux).ServeHTTP(0xc21001e5d0, 0x584500, 0xc21000f460, 0xc2100581a0)
/Users/bsr/Work/ttt/repo/go/src/pkg/net/http/server.go:1496 +0x163
net/http.serverHandler.ServeHTTP(0xc21001f410, 0x584500, 0xc21000f460, 0xc2100581a0)
Is there any way I could modify the request, the url for example, before it gets routed?
If I have two routes like
/client/:id
/client/:client_id/resource
I get a panic
panic: conflict with wildcard route
Is this a feature? I was just not expecting having different wildcard names to cause an issue.
Also the panic message does not provide much of a hint of which routes are causing the issue.
Thanks.
HEAD requests are only occasionally needed, but if your API omits them that causes a problem. It should be easy to add HEAD support.
Testing in Go 1, I am getting:
../../julienschmidt/httprouter/tree.go:297: function ends without a return statement
Check it out:
https://travis-ci.org/gin-gonic/gin/jobs/29068491
I am not sure how to do this... is there support for this? It seems the API does not allow for such thing.
Am I correct in assuming that the design that allows for quick route matching also restricts the routes themselves to being case sensitive?
e.g. For the given route with a named paramter
func Hello(w http.ResponseWriter, r *http.Request, vars map[string]string) {
fmt.Fprintf(w, "Hello, %s!\n", vars["name"])
}
func main() {
router := httprouter.New()
router.GET("/hello/:name", Hello)
log.Fatal(http.ListenAndServe(":12345", router))
}
Is there any way to always return Hello Joe
for the following requests?
/hello/Joe
/HELLO/Joe
/hElLo/Joe
i.e. The desire is to have the route be case insensitive with the values of named parameters retaining their casing.
Hi Julien
The router currently returns 404 Not Found even if the path (and thus the resource) exists but the request method does not match. In such a situation, to be a good HTTP citizen, it should return 405 Method Not Allowed and indicate the available methods for the desired resource in the "Allow" header.
I've looked into your router implementation. The way the routes are currently organized, doing this wouldn't be that easy (and fast) because you have a separate tree for each request method. I think you should have one tree instead and store the defined methods along with their handlers in the node structure.
To customize the server response, in addition to the NotFound handler to be found in the Router structure, there should also be a MethodNotAllowed handler. It should be passed a list of allowed methods.
Regards,
Claudio
I'm not sure what catchPanic is, but it is undefined with testing I have for this package.
It seems there's currently no way to handle all methods with a handler. Would it be possible to add something like support for specifying * (or nil) as the method, and have that be called if an explicit method is not provided?
In my particular case, I need to process chunks of a URL regardless of the method and pass the request on to a proxy.
This is more of general question than a real issue, I am fairly new to go and I am trying to convert some of our ruby projects over to go using httprouter. Is there a way to have httproute handle params in the url? something like http://example.com/generate?user=12&group=mygroup
I have tried to set a general generate
route and read the params, but I keep getting params as empty
Any plan for supporting it?
Hello,
how can I use this together with Google App Engine?
Here is a working example that uses the net/http
library:
package main
import (
"fmt"
"net/http"
)
func init() {
http.HandleFunc("/", index)
}
func index(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "Hello, world!")
}
I tried to do the same with httprouter
:
package main
import (
"fmt"
"net/http"
"github.com/julienschmidt/httprouter"
)
func init() {
router := httprouter.New()
router.GET("/", index)
}
func index(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
fmt.Fprint(w, "Hello, world!")
}
But it doesnt work. I always get 404 page not found
.
Hi,
I could not understand why the error is happening, since I'm not using wildcard routes. I think this could be a bug.
package main
import (
"fmt"
`github.com/julienschmidt/httprouter`
"log"
"net/http"
)
func main() {
router := httprouter.New()
router.GET(`/assets/:type/:asset`, Debug)
router.GET(`/:year/:month/:day/:slug`, Debug)
router.GET(`/`, Index)
log.Fatal(http.ListenAndServe(`:8080`, router))
}
func Index(rw http.ResponseWriter, req *http.Request, params httprouter.Params) {
fmt.Fprint(rw, "Home page with summary of blog posts\n")
}
func Debug(rw http.ResponseWriter, req *http.Request, params httprouter.Params) {
fmt.Fprintf(rw, "debug, %s\n", params)
}
Here is the relevant part of the dump:
goroutine 16 [running]:
runtime.panic(0x5f05c0, 0xc208000740)
/usr/local/go/src/pkg/runtime/panic.c:279 +0xf5
github.com/julienschmidt/httprouter.(*node).insertChild(0xc208004180, 0xc208000704, 0x6c9811, 0x17, 0x715b78)
.../Go/src/github.com/julienschmidt/httprouter/tree.go:201 +0x11e
github.com/julienschmidt/httprouter.(*node).addRoute(0xc208004180, 0x6c9811, 0x17, 0x715b78)
.../Go/src/github.com/julienschmidt/httprouter/tree.go:172 +0x952
github.com/julienschmidt/httprouter.(*Router).Handle(0xc20800e4e0, 0x696fd0, 0x3, 0x6c9810, 0x18, 0x715b78)
.../Go/src/github.com/julienschmidt/httprouter/router.go:205 +0x186
github.com/julienschmidt/httprouter.(*Router).GET(0xc20800e4e0, 0x6c9810, 0x18, 0x715b78)
.../Go/src/github.com/julienschmidt/httprouter/router.go:159 +0x59
main.main()
.../Go/src/.../main.go:13 +0xb5
Hello,
you write yourself that there is no efficient way to retrieve parameters without providing a third parameter.
I thought of four possible ways which we see partly in other routers:
request.URL.Query()
patThe third one would require another extraction of the route parameter but as it is optional and does not require any extra cache layer I think it could be still efficient (if this is your main concern).
Best,
Bo
Hi Julien,
I just set up a project called Swugger to show how swagger support might be acheived for httprouter. It's working, and it uses go-restful's swagger support to document some 'dummy' go-restful routes while setting up real routes in httprouter. I'd like to actually just fork go-restful and strip it back into a swagger provider for httprouter (and others), but before I do that I'd like to check in with you first.
So, I have 2 questions:
Firstly, have you considered Swagger support already? Or any other form of service description feature? Are you already working on something like this for httprouter? For example, it might be nice to optionally represent routing documentation inside httprouter's node
, but then on the other hand, it would add baggage to a small and tidy framework.
Secondly, if you're interested at all, could you take a look at swugger (see the readme), and see if it's an interesting idea to you. If you have any feelings about how you might do things differently, I'd love to know.
Feedback aside I'll just go ahead and make a less 'ugger' version of swugger (forking and stripping back go-restful back towards swagger support only. I may also change it to use a less fluent-interface style of library - just adding a RouteDoc{} struct to each route definition might feel more Go-ish to me).
Anyway, there it is, thanks for the awesome work on making a fast router.
Would it be possible to support "{}" for named parameters. This is according to http://tools.ietf.org/html/rfc6570 May be configurable so that one can use ":" or {}.
What do you think about making the Lookup
method (or a similar one) more generic in terms of not enforcing a specific function footprint?
Currently, when building something on top of httprouter
, each handler has to be a func(w http.ResponseWriter, r *http.Request, _ httprouter.Params)
. It would be nice if the Lookup
method (or a similar one) returns an interface{}
, while httprouter
itself still enforces the httprouter.Handle
type for its own public API. This would allow using custom handle types for modules build on top of httprouter
.
Hi!,
When I use this ...
router.ServeFiles("/static/*filepath", http.Dir("/var/www/static"))
It works, but this show the directories, there are any way for disable the directory listing? (without insert a empty index.html in every dir)
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.