diff --git a/__tests__/response/back.js b/__tests__/response/back.js new file mode 100644 index 000000000..cd28fd94f --- /dev/null +++ b/__tests__/response/back.js @@ -0,0 +1,32 @@ +'use strict' + +const assert = require('assert') +const context = require('../../test-helpers/context') + +describe('ctx.back([alt])', () => { + it('should redirect to Referrer', () => { + const ctx = context() + ctx.req.headers.referrer = '/login' + ctx.back() + assert.equal(ctx.response.header.location, '/login') + }) + + it('should redirect to Referer', () => { + const ctx = context() + ctx.req.headers.referer = '/login' + ctx.back() + assert.equal(ctx.response.header.location, '/login') + }) + + it('should default to alt', () => { + const ctx = context() + ctx.back('/index.html') + assert.equal(ctx.response.header.location, '/index.html') + }) + + it('should default redirect to /', () => { + const ctx = context() + ctx.back() + assert.equal(ctx.response.header.location, '/') + }) +}) diff --git a/lib/context.js b/lib/context.js index fafe1ec51..7cd06bef4 100644 --- a/lib/context.js +++ b/lib/context.js @@ -204,6 +204,7 @@ delegate(proto, 'response') .method('set') .method('append') .method('flushHeaders') + .method('back') .access('status') .access('message') .access('body') diff --git a/lib/response.js b/lib/response.js index 8893fcba5..5cda6ce60 100644 --- a/lib/response.js +++ b/lib/response.js @@ -18,6 +18,7 @@ const only = require('./only.js') const util = require('util') const encodeUrl = require('encodeurl') const Stream = require('stream') +const deprecate = require('depd')('koa') /** * Prototype. @@ -293,7 +294,11 @@ module.exports = { redirect (url, alt) { // location - if (url === 'back') url = this.ctx.get('Referrer') || alt || '/' + if (url === 'back') { + deprecate('Special-cased string "back" through redirect will be removed in v3, ' + + 'consider migrating usage to ctx.back() instead.') + url = this.ctx.get('Referrer') || alt || '/' + } if (/^https?:\/\//i.test(url)) { // formatting url again avoid security escapes url = new URL(url).toString() @@ -316,6 +321,24 @@ module.exports = { this.body = `Redirecting to ${url}.` }, + /** + * Perform a special-cased "back" to provide Referrer support. + * When Referrer is not present, `alt` or "/" is used. + * + * Examples: + * + * ctx.back() + * ctx.back('/index.html') + * + * @param {String} [alt] + * @api public + */ + + back (alt) { + const url = this.ctx.get('Referrer') || alt || '/' + this.redirect(url) + }, + /** * Set Content-Disposition header to "attachment" with optional `filename`. *