kit icon indicating copy to clipboard operation
kit copied to clipboard

Clientside link navigation doesn't respect redirects

Open styxpilled opened this issue 3 years ago • 1 comments

Describe the bug

When using SvelteKit's clientside link navigation, redirects are not being respected unless the link has the data-sveltekit-reload attribute. If a page returns a redirect, Kit just throws a 500 Internal Error for the user (no message on the server). You can verify that the responses are getting sent correctly and have 3xx status codes by checking devtools.

This happens both when redirecting from hooks.server.ts and +page.server.ts.

When using the data-sveltekit-reload or manually refreshing the page, the redirect works fine.

It doesn't seem to matter how the redirect is sent: Kit's redirect() error, Response(null, { status: 302, headers: { Location: '/login' } }), and Response.redirect(event.url.origin + '/login', 302); all give the same result.

I couldn't find any docs on this, so I assume this is either unintended behavior or I'm doing something wrong.

Reproduction

https://github.com/styxpilled/sveltekit-navigation-redirect-issue

Logs

No response

System Info

System:
    OS: Windows 10 10.0.19044
    CPU: (4) x64 Intel(R) Core(TM) i3-9100F CPU @ 3.60GHz
    Memory: 453.96 MB / 15.94 GB
  Binaries:
    Node: 18.11.0 - ~\AppData\Local\pnpm\node.EXE
    npm: 8.19.2 - ~\AppData\Local\pnpm\npm.CMD
  Browsers:
    Edge: Spartan (44.19041.1266.0), Chromium (107.0.1418.56)
    Internet Explorer: 11.0.19041.1566

Severity

annoyance

Additional Information

No response

styxpilled avatar Nov 23 '22 20:11 styxpilled

The issue happens when clicking the link, the router always makes a request to /.../__data.json and expects JSON, but hooks.server is returning HTML because of the redirect.

  1. Client sends a request and expects JSON
  2. Client renders the error page because response is not JSON
// error log in the browser
SyntaxError: Unexpected token '<', "<!DOCTYPE "... is not valid JSON
CleanShot 2022-11-24 at 12 00 23@2x

https://stackblitz.com/edit/sveltejs-kit-template-default-1hgftc?file=README.md,src%2Fhooks.server.js&terminal=dev

teemingc avatar Nov 24 '22 04:11 teemingc

This is marked as fixed, but I am still having issues with redirects in client-side navigation. I have simple link like this:

<a href="/signout?u={encodeURIComponent($page.url.href)}">Sign Out</a>

And I have a routes/signout/+page.server.ts with:

import db from "$lib/server/db";
import { signOut } from "$lib/server/user-session";
import { redirect } from "@sveltejs/kit";
import type { PageServerLoad } from "./$types";

export const load: PageServerLoad = async ({ cookies, url }) => {
  await signOut(db, cookies);
  throw redirect(302, url.searchParams.get("u") ?? "/");
};

I am using version 1.0.0-next.571 of SvelteKit.

Edit: I can see that __data.json no longer throws an error, it is now json with the redirect info. However no navigation takes place, user is still on the same page as if nothing changed. Is this because I am sending the user to the same URL?

tyler-johnson avatar Dec 04 '22 22:12 tyler-johnson

This is marked as fixed, but I am still having issues with redirects in client-side navigation. I have simple link like this:

<a href="/signout?u={encodeURIComponent($page.url.href)}">Sign Out</a>

And I have a routes/signout/+page.server.ts with:

import db from "$lib/server/db";
import { signOut } from "$lib/server/user-session";
import { redirect } from "@sveltejs/kit";
import type { PageServerLoad } from "./$types";

export const load: PageServerLoad = async ({ cookies, url }) => {
  await signOut(db, cookies);
  throw redirect(302, url.searchParams.get("u") ?? "/");
};

I am using version 1.0.0-next.571 of SvelteKit.

Edit: I can see that __data.json no longer throws an error, it is now json with the redirect info. However no navigation takes place, user is still on the same page as if nothing changed. Is this because I am sending the user to the same URL?

I've tried reproducing the issue here https://stackblitz.com/edit/sveltejs-kit-template-default-vasxyy?file=src/routes/+page.svelte

It is redirecting to the same URL. Is this what you've intended?

If you need to reload data after the signout, you could include a invalidateAll() or change it to a POST form action. I've read that a POST is preferable for a signout because it signifies that there are side-effects. It also avoids the issue of the signout load function being preloaded (calling a signout to the db) when the user hovers over the link. This happens because of SvelteKit's preload link options, which you can also turn off manually or omit from app.html.

teemingc avatar Dec 05 '22 01:12 teemingc

Yep I understand now, this is my own mistake.

Also, I saw in your code there a bug I overlooked, thanks! One of those weird times where || is actually better than ??.

tyler-johnson avatar Dec 05 '22 21:12 tyler-johnson