Yousuf Iqbal Hashim
Yousuf Iqbal Hashim

Reputation: 975

KoaJS ctx.redirect() causing ERR_TOO_MANY_REDIRECTS in Chrome

I'm new to KoaJS. Playing a bit now. I'm trying to redirect all request to a particular URL using a middle-ware. This seems to product ERR_TOO_MANY_REDIRECTS in Chrome. I tried a lot to debug. Can't get what is wrong.

index.js

// App
const Koa = require('koa')
const app = new Koa()

// Parser
const bodyParser = require('koa-body')
app.use(bodyParser())

// Session
const session = require('koa-session')
app.keys = ['asdfasdf@#$ASDf1#$@5rasdf']
app.use(session(app))
// THIS MIDDLEWARE
app.use(async (ctx, next) => {
    ctx.session.user = '121' // This is all playground. No production stuff.
    const s = ctx.session.user
    if (s != '1213') {
        ctx.redirect('/login')
    }
    await next()
})

// Router
const common = require('./routes')
app.use(common.routes())

// Server
app.listen(3000, () => { console.log('Listening on http://localhost:3000') })

routes.js

const Router = require('koa-router')
const router = new Router()

// const User = require('./user')

router.get('/', async ctx => {
    ctx.body = 'Home Page'
})

router.get('/login', async ctx => {
    ctx.body = 'Login Page'
})

module.exports = router

Upvotes: 1

Views: 3135

Answers (1)

robertklep
robertklep

Reputation: 203514

Consider your middleware:

app.use(async (ctx, next) => {
    ctx.session.user = '121' // This is all playground. No production stuff.
    const s = ctx.session.user
    if (s != '1213') {
        ctx.redirect('/login')
    }
    await next()
})

Because s != '1213' always evaluates to "true", ctx.redirect('/login') is executed for every request.

This will do two things:

  • set the HTTP response code to 302, telling the browser to perform a redirect
  • set the Location header to /login, telling the browser to location to redirect to

Considering that this happens for every request, you end up in a loop: a request to / is redirected to /login, which itself is redirected to /login, which is also redirected to /login, ad infinitum. At some point, the browser gives up and issues a ERR_TOO_MANY_REDIRECTS error.

FWIW, after calling ctx.redirect(), you typically end the request, for instance like this:

if (s != '1213') {
    return ctx.redirect('/login')
}

In your case, you don't end the request, which means that it will be passed to the router.

To answer your comment, I assume you used this:

if (s != '1213') {
    ctx.url = '/login';
}

You change the URL that the router will check to see which handler it should call. Sort of like an internal redirect, or a "rewrite": a request to / is handled internally as if it were a request for /login.

This is not something that you want though, because it may confuse the browser. The correct way is to issue a proper redirect, using ctx.redirect(), which will make the browser change the URL in the location bar and issue a new request.

Upvotes: 2

Related Questions