Merge pull request #2265 from clarkdo/external_url

feat: allow redirect to external url
This commit is contained in:
Sébastien Chopin 2017-11-28 10:52:14 +01:00 committed by GitHub
commit 887ebd5e25
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 110 additions and 5 deletions

View File

@ -7,6 +7,9 @@ export default {
name: 'nuxt',
props: ['nuxtChildKey'],
render(h) {
if (this.nuxt._redirected) {
return h('div', [ 'redirecting.' ])
}
// If there is some error
if (this.nuxt.err) {
return h('nuxt-error', {

View File

@ -132,11 +132,23 @@ export async function setContext(app, context) {
path = status
status = 302
}
app.context.next({
path: path,
query: query,
status: status
})
if (path.charAt(0) === '/' && path.charAt(1) !== '/') {
app.context.next({
path: path,
query: query,
status: status
})
} else {
path = formatUrl(path, query)
if (process.server) {
app.context.res.setHeader('Location', path)
app.context.res.statusCode = status
app.nuxt._redirected = true
}
if (process.client) {
window.location = path
}
}
}
if (process.server) app.context.beforeNuxtRender = (fn) => context.beforeRenderFns.push(fn)
if (process.client) app.context.nuxtState = window.__NUXT__
@ -442,3 +454,60 @@ function escapeString(str) {
function escapeGroup(group) {
return group.replace(/([=!:$\/()])/g, '\\$1')
}
/**
* Format given url, append query to url query string
*
* @param {string} url
* @param {string} query
* @return {string}
*/
function formatUrl (url, query) {
let protocol
let index = url.indexOf('://')
if (index !== -1) {
protocol = url.substring(0, index)
url = url.substring(index + 3)
} else if (url.indexOf('//') === 0) {
url = url.substring(2)
}
let parts = url.split('/')
let result = (protocol ? protocol + '://' : '//') + parts.shift()
let path = parts.filter(Boolean).join('/')
let hash
parts = path.split('#')
if (parts.length === 2) {
path = parts[0]
hash = parts[1]
}
result += path ? '/' + path : ''
if (query && JSON.stringify(query) !== '{}') {
result += (url.split('?').length === 2 ? '&' : '?') + formatQuery(query)
}
result += hash ? '#' + hash : ''
return result
}
/**
* Transform data object to query string
*
* @param {object} query
* @return {string}
*/
function formatQuery (query) {
return Object.keys(query).sort().map(key => {
var val = query[key]
if (val == null) {
return ''
}
if (Array.isArray(val)) {
return val.slice().map(val2 => [key, '=', val2].join('')).join('&')
}
return key + '=' + val
}).filter(Boolean).join('&')
}

View File

@ -143,6 +143,15 @@ test('/redirect2', async t => {
t.is(await page.$text('h1'), 'Index page')
})
test('/redirect3', async t => {
// New page for redirecting to external link.
const page = await browser.page(url('/'))
await page.nuxt.navigate('/redirect3', false)
await page.waitForFunction(() => window.location.href === 'https://nuxtjs.org/')
page.close()
t.pass()
})
test('/no-ssr', async t => {
await page.nuxt.navigate('/no-ssr')

View File

@ -117,6 +117,19 @@ test('/redirect -> check redirected source', async t => {
t.true(html.includes('<h1>Index page</h1>'))
})
test('/redirect -> external link', async t => {
const headers = {}
const { html } = await nuxt.renderRoute('/redirect3', {
res: {
setHeader(k, v) {
headers[k] = v
}
}
})
t.is(headers.Location, 'https://nuxtjs.org')
t.true(html.includes('<div>redirecting.</div>'))
})
test('/special-state -> check window.__NUXT__.test = true', async t => {
const window = await nuxt.renderAndGetWindow(url('/special-state'))
t.is(window.document.title, 'Nuxt.js')

11
test/fixtures/basic/pages/redirect3.vue vendored Normal file
View File

@ -0,0 +1,11 @@
<template>
<div>Redirecting...</div>
</template>
<script>
export default {
fetch({ redirect }) {
return redirect('https://nuxtjs.org/')
}
}
</script>