无法使用 NoRoute 函数为 vue.js SPA 应用提供服务
Can't serve vue.js SPA app using the NoRoute function
我有一个项目正在建立一个 gin-server 在同一个 docker 容器中托管 api 和 SPA vue.js 应用程序:
code
├── main.go
├── Routes
│ └── Routes.go
├── Controllers
│ ├── Controllers.go
│ ...
└── web
├── src
│ └── App.vue
├── dist
├── public
...
当前端托管在开发人员 js 服务器中时,前端运行良好,单独 api 也运行良好,但是当我在 gin-server 中托管 vue.js 应用程序时,后端 gin 路由器在常规“/”路由中显示我的应用程序,但在尝试访问由 VueRouter 管理的子路由时给我 404。我希望能够将不属于 api 的任何内容路由到 VueRouter,我的代码基于一些指南,还尝试解决我在产品中发现的问题但没有运气:
这是我的 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
我可以使用 OKTA 配置身份验证,问题是当 OKTA 服务器重定向到回调 url 时 /implicit/callback... 它只提供 404 而不是为 vue 提供服务路线。
对于遇到此问题的任何人,我能够通过删除我从问题中复制的所有中间件并简单地使用 gin-static 中间件来解决我的问题:
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")
})
我有一个项目正在建立一个 gin-server 在同一个 docker 容器中托管 api 和 SPA vue.js 应用程序:
code
├── main.go
├── Routes
│ └── Routes.go
├── Controllers
│ ├── Controllers.go
│ ...
└── web
├── src
│ └── App.vue
├── dist
├── public
...
当前端托管在开发人员 js 服务器中时,前端运行良好,单独 api 也运行良好,但是当我在 gin-server 中托管 vue.js 应用程序时,后端 gin 路由器在常规“/”路由中显示我的应用程序,但在尝试访问由 VueRouter 管理的子路由时给我 404。我希望能够将不属于 api 的任何内容路由到 VueRouter,我的代码基于一些指南,还尝试解决我在产品中发现的问题但没有运气:
这是我的 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
我可以使用 OKTA 配置身份验证,问题是当 OKTA 服务器重定向到回调 url 时 /implicit/callback... 它只提供 404 而不是为 vue 提供服务路线。
对于遇到此问题的任何人,我能够通过删除我从问题中复制的所有中间件并简单地使用 gin-static 中间件来解决我的问题:
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")
})