Reputation: 119
I have a project which is establishing a gin-server hosting both the api and a SPA vue.js app in the same docker container:
code
├── main.go
├── Routes
│ └── Routes.go
├── Controllers
│ ├── Controllers.go
│ ...
└── web
├── src
│ └── App.vue
├── dist
├── public
...
The frontend is working well when its hosted in the developer js server and the api alone also working well but when I host the vue.js app in the gin-server, the backend gin router show my app in regular "/" route but gives me 404 when trying to get to my subroutes managed by th VueRouter. I want to be able to route whatever is not part of the api to the VueRouter, I based my code on a few guides, also tried to tackle it with issues that i found in the product but no luck:
this is my Routes.go:
package Routes
import (
"path"
"strings"
"devops-portal/Controllers"
"github.com/gin-gonic/gin"
"net/http"
"github.com/gobuffalo/packr/v2"
)
//SetupRouter ... Configure routes
func SetupRouter() *gin.Engine {
r := gin.Default()
webFiles := packr.New("web app", "../web/dist")
r.Use(StaticServe("/", webFiles))
grp1 := r.Group("/api/v1")
{
grp1.GET("request", Controllers.GetRequests)
grp1.POST("create-request", Controllers.CreateRequest)
grp1.GET("request/:id", Controllers.GetRequestByID)
grp1.PUT("request/:id", Controllers.UpdateRequest)
grp1.DELETE("request/:id", Controllers.DeleteRequest)
}
r.NoRoute(func(c *gin.Context){
c.File("../web/dist/index.html")
})
return r
}
func ReturnPublic() gin.HandlerFunc {
return func(context *gin.Context) {
method := context.Request.Method
if method == "GET" {
context.File("./public")
} else {
context.Next()
}
}
}
func exists(fs *packr.Box, prefix string, filepath string) bool {
if p := strings.TrimPrefix(filepath, prefix); len(p) < len(filepath) {
name := path.Join("/", p)
if fs.HasDir(name) {
index := path.Join(name, "index.html")
if !fs.Has(index) {
return false
}
} else if !fs.Has(name) {
return false
}
return true
}
return false
}
// StaticServe serves the web app
func StaticServe(urlPrefix string, fs *packr.Box) gin.HandlerFunc {
fileserver := http.FileServer(fs)
if urlPrefix != "" {
fileserver = http.StripPrefix(urlPrefix, fileserver)
}
return func(c *gin.Context) {
if exists(fs, urlPrefix, c.Request.URL.Path) {
fileserver.ServeHTTP(c.Writer, c.Request)
c.Abort()
}
}
}
VueRouter - web/src/router/index.js:
import Vue from 'vue'
import VueRouter from 'vue-router'
import Auth from '@okta/okta-vue'
Vue.use(Auth, {
issuer: 'https://xxxxx.okta.com/',
client_id: 'xxxxxxxxxxxxxxxx',
redirect_uri: 'http://localhost:3000/implicit/callback',
scope: 'openid profile email',
pkce: true
})
Vue.use(VueRouter)
const routes = [
{ path: '/login', name: 'Login', component: () => import('../views/Login.vue')},
{ path: '/', name: 'Home', component: () => import('../views/requests.vue'), meta: { requiresAuth: true }},
{ path: '/requests', name: 'Requests', component: () => import('../views/requests.vue'), meta: { requiresAuth: true }},
{ path: '/implicit/callback', component: Auth.handleCallback() }
]
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes
})
router.beforeEach(Vue.prototype.$auth.authRedirectGuard());
export default router
As you can I configured authentication with OKTA, the problem is when the OKTA servers is redirecting to the callback url which is /implicit/callback... It just gives 404 instead of serving the vue route.
Upvotes: 2
Views: 2136
Reputation: 119
To anyone experiencing this issue i was able to solve my problem by removing all the middleware i copied from the issues and simply use the gin-static middleware:
r := gin.Default()
r.Use(static.Serve("/", static.LocalFile("./web/dist", true)))
grp1 := r.Group("/api/v1")
{
grp1.GET("request", Controllers.GetRequests)
grp1.POST("create-request", Controllers.CreateRequest)
grp1.GET("request/:id", Controllers.GetRequestByID)
grp1.PUT("request/:id", Controllers.UpdateRequest)
grp1.DELETE("request/:id", Controllers.DeleteRequest)
}
r.NoRoute(func(c *gin.Context){
c.File("./web/dist/index.html")
})
Upvotes: 3