Skip to content

Detecting redirects #1822

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
callumacrae opened this issue Oct 17, 2017 · 7 comments
Closed

Detecting redirects #1822

callumacrae opened this issue Oct 17, 2017 · 7 comments
Labels
feature request fixed on 4.x This issue has been already fixed on the v4 but exists in v3 group[current route information] Issues regarding current route information that is currently missing

Comments

@callumacrae
Copy link

What problem does this feature solve?

With vue-router 1.x, it was possible to see where a route had been redirected from using router.currentRoute.redirectedFrom. This was useful when server-side rendering, as you could send a 301 from the server instead of sending the HTML for the new page and then changing the URL on the client.

With 2.x, the property has gone and I can't find it anywhere. Has it been removed? If so, it would be great if it could come back!

Reason it was nice that it existed: #968

What does the proposed API look like?

router.currentRoute.redirectedFrom === '/old-path'

@callumacrae
Copy link
Author

image

Hahaha was I the only person using this? nice.

@andrey-hohlov
Copy link

andrey-hohlov commented Oct 28, 2017

Solution (in entry-server.js):

import { createApp } from './app';

export default context => new Promise((resolve, reject) => {
  const { app, router, store } = createApp();

  console.log(router.resolve(context.url).route); // object has redirectedFrom property

  router.push(context.url);

  router.onReady(() => { /* ... */ }, reject);
});

@joenoon
Copy link

joenoon commented Jan 28, 2018

In case this helps anyone, after some digging I found that luckily when you push/replace a route, there is a pending property that gets set with that route:

this.pending = route

On the server-side, in your entry-server, you can add router and fullPath to context. Something like:

// ...
    const route = router.resolve(url).route

    const { fullPath } = route;

    if (fullPath !== url) {
      return reject({ url: fullPath })
    }

    context.fullPath = fullPath;
    context.router = router;

    // set router's location
    router.push(url)
// ...

That part doesn't handle the case of a redirect the app makes after loading data and trying to render.

To address that, back inside the server/express side where you call renderToString, you can detect those redirects and handle:

// ...
    renderer.renderToString(context, (err, html) => {
      if (err) {
        return handleError(err)
      }
      const {pending} = context.router.history;
      if (pending) {
        if (pending.fullPath !== context.fullPath) {
          console.log(`redirect ${context.fullPath} to ${pending.fullPath}`);
          return res.redirect(301, pending.fullPath);
        }
      }
      res.send(html)
    });
// ...

Hope this helps! And if there is a better way, let me know.

@NoraGithub
Copy link

@joenoon What do you mean by your solution? Caz if your url is not the same,

    if (fullPath !== url) {
      return reject({ url: fullPath })
    }

it would directly reject the req and would not do the redirect any longer. As far as I am concerned, It should be solved in the handleError

@joenoon
Copy link

joenoon commented Mar 27, 2018

@NoraGithub its a bit different case. the fullPath !== url is the easy one, where the router instantly knows it is a redirect.

The second one is harder, where async data is fetched, and a component ends up reacting to the data and decides to redirect instead. For example, when a user profile component is loaded, the component fetches the user but discovers the user no longer exists. The component does something like if (!user) this.$router.push('/').

Your component still likely rendered something, like an empty <div></div> etc. But the server side is now able to see the component is also trying to redirect.

@xMartin
Copy link

xMartin commented Jul 27, 2018

router.currentRoute.redirectedFrom actually does exist in version 3:

route.redirectedFrom = getFullPath(redirectedFrom, stringifyQuery)

To me this should not be a feature request but it's rather a documentation issue. With the hints from the comments above there could be a nice how-to.

@posva posva added the group[current route information] Issues regarding current route information that is currently missing label Mar 26, 2019
@posva posva added the fixed on 4.x This issue has been already fixed on the v4 but exists in v3 label Apr 20, 2020
@posva posva closed this as completed Apr 22, 2020
@posva
Copy link
Member

posva commented Apr 22, 2020

in Vue Router 3 redirectedFrom only exists for records with a redirect option. In Vue Router 4, it will also exist for redirections made with navigation guards

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature request fixed on 4.x This issue has been already fixed on the v4 but exists in v3 group[current route information] Issues regarding current route information that is currently missing
Projects
None yet
Development

No branches or pull requests

6 participants