Next.js Discord

Discord Forum

Cannot redirect using route handler

Answered
Spectacled bear posted this in #help-forum
Open in Discord
Spectacled bearOP
Hi, I have a route handler to handle login. When user calls this endpoint, I expect to redirect them to a different page. However, when I use redirect or NextResponse.redirect, the redirecting does not work.

I follow this section: https://nextjs.org/docs/app/building-your-application/routing/route-handlers#redirects

I have included a photo of the network tab. I still receive a 307 response in frontend and the whole page load but the UI is not changing.

I have tried using form action and client event handler but no luck so far

Here is a repo I use to recreate this behavior: https://github.com/trungne/nextjs-route-handler-redirect

Not sure if I understand the docs correctly but I would expect the UI to be redirected to a new page when I perform redirect in a route handler.

Any help is appreciated. Thanks!
Answered by Western paper wasp
From a route handler, NextResponse.redirect() will redirect the request it’s handling
View full answer

26 Replies

It seems that redirect is not allowed in the api
why are you trying to do it on the api side?
Western paper wasp
From a route handler, NextResponse.redirect() will redirect the request it’s handling
Answer
Western paper wasp
For example, if you visit the path of that route handler in your browser directly, you should be redirected.
However, if you’re making a request to the route from JavaScript, e.g. using fetch, it’s this fetch call which will be redirected to the new page, not the browser session
Like, if you fetch('/api/login') and /api/login returns a 307 to https://nextjs.org, your fetch will be redirected, equivalent to if you had written fetch('https://nextjs.org')
But you would not expect fetch('https://nextjs.org') to redirect the browser window to nextjs.org
Network requests get redirected all the time, and fetch follows redirects automatically.
but your fetch request being redirected is very different from the whole page being redirected
a 307 would only change the page if the first / “main” request to your app responded with a 307
does that make sense?
American Crow
tell him how to redirect client side / the browser session and the answer is complete
if you dont mind
Western paper wasp
You can perform the redirect using Javascript once your fetch call is completed:
fetch("/api/login", {
  method: "GET",
}).then(() => { window.location = 'https://nextjs.org' });
In your github example, i think it‘s a mistake that your action is a server action (“use server”) and it’s calling the API route as /api/login.
Calling an API route as /api/login will only work from the client, but server actions run on the server side. This is because the server doesn’t know the “base URL” of your app, and can’t make a request without a full URL.
American Crow
or the nextjs way
const router = useRouter()
...
const response = await fetch("/api/login")
if (response.status === 307) {
  router.push('/login')
}
Western paper wasp
I used window.location because in his example, the redirect is to an external site rather than an internal page
American Crow
oh i didnt even read that part
my apologies
Western paper wasp
router.push('https://nextjs.org') does nothing beyond setting window.location

But if you’re redirecting to a page within your app, you should use router.push as @American Crow shows
@Western paper wasp In your github example, i think it‘s a mistake that your `action` is a server action (“`use server`”) and it’s calling the API route as `/api/login`.
Western paper wasp
Since your server action already runs on the server, it’s both difficult and wasteful to do an API call to your own app.

You should just call a login function in your server action, and run the redirect in the server action. You should can cut out the API call.

This should work:
      <form
        action={async () => {
          "use server";
          redirect('https://nextjs.org');
        }}
      >
American Crow
here is a resource what @Western paper wasp said. Using Route Handlers wiht Server components is common mistake #1 but a no no
https://vercel.com/blog/common-mistakes-with-the-next-js-app-router-and-how-to-fix-them
@Western paper wasp In your github example, i think it‘s a mistake that your `action` is a server action (“`use server`”) and it’s calling the API route as `/api/login`.
Western paper wasp
alternatively, you can do the whole thing on the client:
      <form
        onSubmit{(e) => {
          e.preventDefault();
          fetch("/api/login").then((r) => {
            if (r.status > 300 && r.status < 400) {
              window.location.href = r.headers.get('Location');
            }
          });
        }}
      >
But the way your code is written (making a call to your Route Handler from a Server Action) is incorrect
Spectacled bearOP
I get it now. Thank you so much for the detailed explanation. Cheers 🙌