Vue-router: Hash mode places # at incorrect location in URL if current query parameters exist on page load

Created on 23 Mar 2018  ·  21Comments  ·  Source: vuejs/vue-router

Version

3.0.1

Reproduction link

https://codesandbox.io/s/zlvz65rplp

Steps to reproduce

Navigate to myapp.com?foo=bar

What is expected?

Hash is appended before query parameters, to get the final result of myapp.com/#/?foo=bar

What is actually happening?

Hash is placed after parameters myapp.com?foo=bar#/ (also making the query parameters inaccessible with this.$route.query)


Note on codesandbox link - unable to place query parameter for initial URL in editor preview - please remove /#/ & append ?foo=bar

Running across this in an instance where user authentication is done outside our app, but client/user identifier is passed to our app in query parameter upon authorization.

Most helpful comment

I'm also having this same issue when trying to use oauth with github. My callback url is set to https://myurl.com/#/ in github and when I get redirected it's still redirecting me to https://myurl.com?code=1234567890#/

All 21 comments

Next time, please take the time to complete the repro, it would have taken you 2 minutes.

@posva Would have done it if I knew how to technically make it happen with codesandbox!

Note on codesandbox link - unable to place query parameter for initial URL in editor preview - please remove /#/ & append ?foo=bar

What I meant is completing the code : adding one route, injecting the router and displaying query params.

Firgot to say, a workaround for this is setting up a route rewrite in your server

@posva Respectfully, I'm not sure we're on the same page. The only thing needed to reproduce this issue is importing vue-router & setting the correct path, which I did here:

export default new Router({
  path: "/"
});

Adding anything else would be extraneous fluff.

The prominent issue here (and this is my fault for a poor title) isn't necessarily that it cannot detect the query parameters that precede the hash — the issue is that upon initially landing on an application that contains query parameters in the URL, the hash is being injected into the URL at the wrong place (after the query params instead of preceding them).

A side-effect of this is this.$route.query not being able to detect the parameters, but I'm not convinced it should. From a maintainers perspective, keep it as simple as possible, right?

I appreciate the workaround! As a matter of due diligence, I already researched this issue prior and was aware of the workaround, but going back to my original issue:

Running across this in an instance where user authentication is done outside our app, but client/user identifier is passed to our app in query parameter upon authorization.

I probably didn't make this clear enough, but in my specific case, I'm not able to control the server or the URL directing to our app - so unfortunately I cannot apply the workaround.

Edited title to better reflect core issue. I don't believe vue-router should try to support detecting query params before /#/

Respectfully, I'm not sure we're on the same page. The only thing needed to reproduce this issue is importing vue-router & setting the correct path, which I did here:

Well, for starters, since you did not actually add the router to the app in new Vue, you missed that your router config was incorrect (but unrelated) to this issue.

I fixed this for you: https://codesandbox.io/s/5wpjknyy6x

I'm also having this same issue when trying to use oauth with github. My callback url is set to https://myurl.com/#/ in github and when I get redirected it's still redirecting me to https://myurl.com?code=1234567890#/

Note that the workaround (see below) referenced in the other issue is unsatisfactory because

  1. URLSearchParams does not have full cross-browser support
  2. It still leaves the # after the query string for the rest of the session which is not acceptable to an end user
const query = (new URLSearchParams(window.location.search.substring(1)));
    if (query.has('code') && query.has('state')) {

Hey @posva,

Is it possible to get a link to the PR I brief look at outstanding PR's and could not find it, or am I misunderstanding the tag?

Cheers.

Using both the latest dev and also b7715dc a hash is still placed at the end of the URI on load, which breaks query params.

As far as I can tell this issue was not fixed.

What was the url that didn't work on the dev branch?

@posva It's not fixed on the latest dev branch for me either. The url doesn't matter, it could be anything that has a query string already in it but not a hash. ie http://example.com/?foo=bar will get turned into http://example.com/?foo=bar#/

The problem with this is that I can't ever get rid of the query string, no matter how I redirect to another route. The query string is stuck there forever in the URL.

@posva looks like dist/ was not updated, but I can't make heads or tails on how to fix that. The getURL() function in dist/vue.router.js is much older than in src/ . It might be a good idea to bump up the version number too so folk aren't wasting time in confusion.

I've forked my own version and updated dist, and it works as expected.

dist files are build on release so to test against dev you always must run yarn run build. I will roll a new version soon after writing some missing docs

Since this breaks other usages like Wordpress plugins or any other case where the server uses the query to render a different page (See https://github.com/vuejs/vue-router/issues/2876), we will have to revert this. For those still seeing the problem, there are multiple options

  • use HTML5 history (if you can do this, you should, it offers better SEO, better URLS and benefit from more features)
  • Detect client side if location.search exists and call location.replace with a version that matches your needs, eg:
if (location.search) {
  location.replace(location.pathname + location.hash + location.search)
}

This is a very simple version that might not fulfil every usecase, adapt it to your own needs. The function that allowed this behavior from 3.1.0 to 3.1.1 was this function:

function getUrl (path) {
  const href = window.location.href
  const hashPos = href.indexOf('#')
  let base = hashPos > -1 ? href.slice(0, hashPos) : href

  const searchPos = base.indexOf('?')
  const query = searchPos > -1 ? base.slice(searchPos) : ''
  base = query ? base.slice(0, searchPos) : base

  return `${base}#${path + query}`
}

So you could pass the result of this function to location.replace before Vue Router starts if you need that behavior.

Since from the server perspective post?id=3 is a different url than post?=3, it makes sense to keep that with the search and treat them as different urls. Contrary to that, the hash cannot be read on the server (it is not sent alongside the request)

@posva Can this be enabled via configuration option? Not having this functionality breaks other hosting platforms like Squarespace. It causes the query string to be stuck in the URL forever because going to new routes doesn't strip them out properly. There still is an underlying bug in that case where the query string detected is everything after the FIRST ? , so I still think this will be broken if left untouched.

@posva Can you elaborate how fixing the hash placement after initial page load breaks functionality of the server reading the query strings? That happens before the DOM is loaded, Vue is mounted, etc.

I'm also facing same issue,i will keep watch it.

@posva Maybe I am missing something, and I apologize if I am, but I forked @LinusBorg 's update to the sandbox, updated the versions of Vue to 2.6.11 and Vue-Router to 3.1.5 and also added a simple computed property that gets it's value from the query param and it still appears that the # is being placed after the query params and this.$route.query.foo is undefined.

https://codesandbox.io/s/vue-template-fxmc1

Going to https://fxmc1.csb.app/?foo=123, foo is undefined and the url becomes https://fxmc1.csb.app/?foo=123#/

I would expect it should be https://fxmc1.csb.app/#/?foo=123 and foo would be 123

Is there any news?
Facing the same issue.
Maybe setting the VueRouter to history mode, but that's not satisfactory.
Thanks 🙏

Was this page helpful?
0 / 5 - 0 ratings

Related issues

mitar picture mitar  ·  3Comments

posva picture posva  ·  3Comments

gil0mendes picture gil0mendes  ·  3Comments

marcvdm picture marcvdm  ·  3Comments

druppy picture druppy  ·  3Comments