Feature request: Allow redirects to absolute URLs, SSR and client-side.
We have an app (https://domainr.com) with several legacy URLs, some of which redirect to other websites. We鈥檙e exploring using Nuxt/Vue for our new website and would like to preserve this behavior.
~/pages/_domain/iana.vue
<script>
export default {
fetch ({ params, redirect }) {
redirect(301, `https://www.iana.org/domains/root/db/${params.domain}.html`)
}
}
</script>
Navigate to /com/iana
Redirect to https://www.iana.org/domains/root/db/com.html
(Click here to see expected behavior: https://domainr.com/com/iana)
Redirect to /https:/www.iana.org/domains/root/db/com.html
(local URL)
Nuxt only allows local redirects to a path, which is prepended with router.base
here: https://github.com/nuxt/nuxt.js/blob/dev/lib/app/server.js#L39
I was able to hack a workaround using middleware, but it throws errors on the client and server side. It throws errors and adds an HTML5 history entry for the redirect. Is there a way to stop processing the request process in middleware, hook into vue-router at a lower-level, or use normal vue-router redirects?
https://gist.github.com/ydnar/afd2fdfa90f9579a8188f0bfe418493d
The hack replaces context.redirect
:
function fixRedirect (ctx) {
const _redirect = ctx.redirect
ctx.redirect = function (status, path, query) {
ctx._redirected = true // Nuxt-specific, unnecessary?
// If only 1 or 2 arguments: redirect('/') or redirect('/', { foo: 'bar' })
if (typeof status === 'string' && (typeof path === 'undefined' || typeof path === 'object')) {
query = path || {}
path = status
status = 302
}
path = addQuery(path, query)
if (!isAbsolute(path)) {
_redirect(status, path)
} else if (ctx.isServer && ctx.res) {
ctx.res.writeHead(status, { 'Location': path })
ctx.res.writeHead = function () {} // FIXME: this is evil
ctx.res.end()
ctx.res.end = function () {} // Also evil
_redirect(status, path)
} else if (ctx.isClient && window && window.location) {
window.location = path
ctx.error()
}
}
}
Refined the hack (workaround?) a bit. It now works on server and client side, redirecting to an absolute URL. It overrides the Location
header and sets the HTTP response code by [ab]using the error
function: error({ statusCode: 301, ... })
.
The only remaining issue is the extra history item if the redirect occurs client-side. I wasn鈥檛 able to find a way to hook into vue-router鈥檚 beforeEntry
function.
function fixRedirect (ctx) {
const _redirect = ctx.redirect
ctx.redirect = function (status, path, query) {
// If only 1 or 2 arguments: redirect('/') or redirect('/', { foo: 'bar' })
if (typeof status === 'string' && (typeof path === 'undefined' || typeof path === 'object')) {
query = path || {}
path = status
status = 302
}
path = addQuery(path, query)
if (!isAbsolute(path)) {
_redirect(status, path)
} else if (ctx.isServer && ctx.res) {
ctx.res.setHeader('Location', path)
ctx.error({ statusCode: status, message: `Redirecting to ${path}` })
} else if (ctx.isClient && window && window.location) {
window.location.replace(path)
// This doesn鈥檛 seem to be necessary in more recent builds of Nuxt
// ctx.error({ statusCode: status, message: `Redirecting to ${path}` })
}
}
}
As a bonus, it allows redirect-only pages like this:
pages/_domain/iana.vue
<script>
export default {
fetch ({ params, redirect }) {
redirect(301, `https://www.iana.org/domains/root/db/${params.domain}.html`)
}
}
</script>
I'm adding it for Nuxt 1.0 @ydnar :)
Estimation when will it be released?
Thanks for fixing!
I found a bug in the 1.x.x implementation: the client-side redirect adds an additional history item. Our internal workaround uses window.location.replace(path)
instead of window.location = path
.
Should I file a new bug?
I can't redirect inside a middleware
, it returns an ERR_REDIRECT
but after that it redirect to desired page.
Anything I can do to don't send to this error page?
seems to happen to me too.
Any ETA on this bug fix?
This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.
Most helpful comment
Refined the hack (workaround?) a bit. It now works on server and client side, redirecting to an absolute URL. It overrides the
Location
header and sets the HTTP response code by [ab]using theerror
function:error({ statusCode: 301, ... })
.The only remaining issue is the extra history item if the redirect occurs client-side. I wasn鈥檛 able to find a way to hook into vue-router鈥檚
beforeEntry
function.As a bonus, it allows redirect-only pages like this:
pages/_domain/iana.vue