Redirecting twice in a single Vue navigation

偶尔善良 提交于 2020-12-30 06:11:16

问题


In my Vue app, a user's homepage depends on their role. To ensure that a user is shown the correct homepage, I use this navigation guard:

export default (to, from, next) => {
  const authService = getAuthService()

  if (to.path === '/') {
    // if they've requested the home page, send them to 
    // different pages depending on their role
    if (authService.isUser()) {
      next({ name: 'events' })

    } else if (authService.isAdmin()) {
      next({ name: 'admin-events' })

    } else {
      next()
    }
  }
}

Then when a user successfully logs in, I redirect them to '/'

  this.$router.push({path: '/'))

and the nav guard above redirects them to their role-specific homepage. However, redirecting twice in the course of a single navigation action is not allowed and causes the following error to appear in the console when the second redirection occurs (in the nav guard) `

Uncaught (in promise) Error: Redirected when going from "/login" to "/" via a navigation guard.

Another case in my app where this happens is the 404 component that handles attempts to access non-existent routes, i.e.

  1. User attempts to access invalid route
  2. 404 component redirects back to '/'
  3. Nav guard redirects to user-specific homepage, causing an error

Is there a way I can support these use cases without redirecting twice?


回答1:


tldr: vm.$router.push(route) is a promise and needs to .catch(e=>gotCaught(e)) errors.


This will be changed in the next major@4


Currently@3 errors are not distinguished whether they are NavigationFailures or regular Errors.

The naive expected route after vm.$router.push(to) should be to. Thus one can expect some failure message once there was a redirect. Before patching router.push to be a promise the error was ignored silently. The current solution is to antipattern a .catch(...) onto every push, or to anticipate the change in design and wrap it to expose the failure as result.

Future plans have it to put those informations into the result:

  let failure = await this.$router.push(to);
  if(failure.type == NavigationFailureType[type]){}
  else{}

Imo this error is just by design and should be handled:

hook(route, current, (to: any) => { ... abort(createNavigationRedirectedError(current, route)) ...}

So basically if to contains a redirect it is an error, which kinda is equal to using vm.$router.push into a guard.

To ignore the unhandled error behaviour one can pass an empty onComplete (breaks in future releases):

vm.$router.push(Route, ()=>{})

or wrap it in try .. catch

try {

  await this.$router.push("/")
} catch {

}

which prevents the promise to throw uncaught.


to support this without redirecting twice means you put the guard to your exit:

let path = "/"
navguard({path}, undefined, (to)=>this.$router.push(to||path))

which will polute every component redirecting to home


btw the router-link component uses an empty onComplete


Assumption that redirecting twice is not allowed is wrong.




回答2:


A possible solution might be as follows:

Let's assume that / route points to HomeComponent.

  1. User navigates to /
  2. In created lifecyle hook, get the authService and check user's permission
  3. 2.a. If it's a user -> navigate them to /events route + replace the history
  4. 2.b. If it's an administrator -> navigate them to /admin-events route + replace the history
  5. Add guards for each /events route so a user without permission won't see /admin-events, etc

Bonus: You are now able to add a message to HomeComponent saying "redirecting you to Events page" or "redirecting you to Administrator Events page" (if needed).




回答3:


Another possible solution might be;

  1. Adding a query string parameter to define that user coming to the / route after login. Like ?fromLogin=1
  2. Adding beforeEnter hook to the / route and attaching the navigation guard check on that hook.
  3. If user coming to the / route from login, redirecting them to the role based page.


来源:https://stackoverflow.com/questions/62512168/redirecting-twice-in-a-single-vue-navigation

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!