gin-gonic / contrib

Collection of middlewares created by the community

Home Page:https://gin-gonic.github.io/gin/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Catch all route with static middleware

eduardonunesp opened this issue · comments

I have an Angular app to serve using Static middleware, and AngularJS is a SPA framework, means it needs to catch all kinds of routes. My question is: can I do something like:

r.Use(static.Serve("/*", static.LocalFile("client/build", true)))

@eduardonunesp I don't get what you are trying to ask. Angular uses #/path1/path2 as routing. That is not specified by the server or in this case, gin. You just need to serve a folder (or root path) as static, and let the angular magic do the rest.

@javierprovecho the idea is when you use Angular in HTML5 mode, the app don't use the # just act like non-SPA. For instance when I was using NGINX it needed to config a sort of catch all URL.

To help clarify the idea, please take a look in this article http://www.codelord.net/2015/05/12/angularjs-how-to-setup-pushstate-with-html5mode/

The SPA server is a common pattern for tidy URLs. Angular, React, Aurelia, these all can use # or they can use "pretty" urls without the #, it's up to the server to return the index.html no matter what url is requested.

In node.js I have handled this by catching a 404 and returning the index.html

I'm using a similar strategy using gin:

	router.NoRoute(func(c *gin.Context) {
		c.File("./public/index.html")
	})

The actual implementation will run a regex on the Request.URL.Path and only return index.html when the regex is true. So if you ask for /unknown-image.png you'll still get a 404.

I also plan to server SPA with gin,

@djensen47 ,base on your comments, I have the code

	router.NoRoute(func(c *gin.Context) {
		dir, file := path.Split(c.Request.RequestURI)
		ext := filepath.Ext(file)
		if file == "" || ext == "" {
			c.File("./public/index.html")
		} else {
			// strings.Split(file, "?")
			c.File("./public" + path.Join(dir, file))
		}

	})

but when after adding service workers... I will get lot of error here.
I thought a better SPA support for gin depends on the issue of httprouter.

and there will be lots of scenario to handle
like: https://www.dreambo8563.tech/manifest.28f941dd3f089e9cfec1.js?aa (path with query)
julienschmidt/httprouter#73

I ended up doing this in labstack/echo instead. Echo actually has the plugins required to make this work seemlessly. We also open sourced the project and call it SPArge: https://github.com/BrewdHQ/sparge

@djensen47 yes, echo can support scenario well

Any solution for this to serve spa with frontend routing?

You can handle all the routes by including a separate line for each one of them.
The below example handles 3 routes, that are, '/' '/login' and '/signup'.
I am using reactjs, but i think (not sure!) this will work for other libraries/frameworks (like angular) as well.
(The 'build' folder is obtained by the command 'npm run build' in react.)

router := gin.Default()

router.Use(static.Serve("/", static.LocalFile("./build", true)))
router.Use(static.Serve("/login", static.LocalFile("./build", true)))
router.Use(static.Serve("/signup", static.LocalFile("./build", true)))

router.NoRoute(func(c *gin.Context) {
	c.JSON(404, gin.H{
		"code": "PAGE_NOT_FOUND", "message": "Page not found", // or use c.File("./public/index.html")
	})
})
commented

so what is the final solution?

so what is the final solution?

@amboowang a simple solution is

	//configuration to SAP applications
	router.Use(static.Serve("/", static.LocalFile("./assets/build", true)))
	router.NoRoute(func(c *gin.Context) {
		if !strings.HasPrefix(c.Request.RequestURI, "/api") {
			c.File("./assets/build/index.html")
		}
		//default 404 page not found
	})

What is the difference between using the contrib static module and the built in router.Static? Is the contrib module required to do a root "/" static route? I get an error when trying to do so with r.Static if I have any other routes.

Just to add to that solution which worked for me as well, in the served html file I had a reference to a js file of type

<script src="./myfile.js"></script>

that was causing me trouble while resolved with a path like /path/secondpath and looking ok with just /path

and I had completely forgotten about this head option

<base href="/">

https://stackoverflow.com/a/46273294/2205050