diff --git a/examples/basic/app.js b/examples/basic/app.js index b248d7841..ab33dd9c2 100644 --- a/examples/basic/app.js +++ b/examples/basic/app.js @@ -45,7 +45,7 @@ const router = new VueRouter({ { path: '/', component: Home }, { path: '/foo', component: Foo }, { path: '/bar', component: Bar }, - { path: '/é', component: Unicode }, + { path: encodeURI('/é'), component: Unicode }, { path: '/query/:q', component: Query } ] }) @@ -76,9 +76,9 @@ const vueInstance = new Vue({ /bar -
  • -
  • /é?t=%ñ
  • -
  • /é#%25ñ
  • +
  • +
  • /é?t=%ñ
  • +
  • /é#%25ñ
  • {{ props.route.path }} (with v-slot). diff --git a/examples/hash-mode/app.js b/examples/hash-mode/app.js index ee58238e9..16475ffc8 100644 --- a/examples/hash-mode/app.js +++ b/examples/hash-mode/app.js @@ -45,8 +45,8 @@ const router = new VueRouter({ { path: '/', component: Home }, // all paths are defined without the hash. { path: '/foo', component: Foo }, { path: '/bar', component: Bar }, - { path: '/é', component: Unicode }, - { path: '/é/:unicode', component: Unicode }, + { path: encodeURI('/é'), component: Unicode }, + { path: encodeURI('/é/:unicode'), component: Unicode }, { path: '/query/:q', component: Query, name: 'param' } ] }) @@ -64,10 +64,10 @@ const vueInstance = new Vue({
  • /foo
  • /bar
  • /bar -
  • -
  • /é/ñ
  • -
  • /é/ñ?t=%ñ
  • -
  • /é/ñ#é
  • +
  • +
  • /é/ñ
  • +
  • /é/ñ?t=%ñ
  • +
  • /é/ñ#é
  • /query/A%
  • /query/A% (object)
  • /query/A%2FE
  • diff --git a/src/create-matcher.js b/src/create-matcher.js index 3392b2c07..fcb8a8092 100644 --- a/src/create-matcher.js +++ b/src/create-matcher.js @@ -7,6 +7,7 @@ import { createRoute } from './util/route' import { fillParams } from './util/params' import { createRouteMap } from './create-route-map' import { normalizeLocation } from './util/location' +import { decode } from './util/query' export type Matcher = { match: (raw: RawLocation, current?: Route, redirectedFrom?: Location) => Route; @@ -175,14 +176,6 @@ function matchRoute ( path: string, params: Object ): boolean { - try { - path = decodeURI(path) - } catch (err) { - if (process.env.NODE_ENV !== 'production') { - warn(false, `Error decoding "${path}". Leaving it intact.`) - } - } - const m = path.match(regex) if (!m) { @@ -195,7 +188,7 @@ function matchRoute ( const key = regex.keys[i - 1] if (key) { // Fix #1994: using * with props: true generates a param named 0 - params[key.name || 'pathMatch'] = m[i] + params[key.name || 'pathMatch'] = typeof m[i] === 'string' ? decode(m[i]) : m[i] } } diff --git a/src/create-route-map.js b/src/create-route-map.js index c05896845..01c0836d2 100644 --- a/src/create-route-map.js +++ b/src/create-route-map.js @@ -70,6 +70,14 @@ function addRouteRecord ( path || name )} cannot be a ` + `string id. Use an actual component instead.` ) + + warn( + // eslint-disable-next-line no-control-regex + !/[^\u0000-\u007F]+/.test(path), + `Route with path "${path}" contains unencoded characters, make sure ` + + `your path is correctly encoded before passing it to the router. Use ` + + `encodeURI to encode static segments of your path.` + ) } const pathToRegexpOptions: PathToRegexpOptions = diff --git a/test/unit/specs/create-map.spec.js b/test/unit/specs/create-map.spec.js index 25bdb3d45..57c81afe1 100644 --- a/test/unit/specs/create-map.spec.js +++ b/test/unit/specs/create-map.spec.js @@ -81,6 +81,15 @@ describe('Creating Route Map', function () { ) }) + it('warns about unencoded entities', function () { + process.env.NODE_ENV = 'development' + maps = createRouteMap([{ path: '/é', component: Home }]) + expect(console.warn).toHaveBeenCalledTimes(1) + expect(console.warn.calls.argsFor(0)[0]).toMatch( + 'vue-router] Route with path "/é"' + ) + }) + it('in development, throws if path is missing', function () { process.env.NODE_ENV = 'development' expect(() => {