[]previous and next page

Client navigations and server middleware (the navigation check)

A client navigation into a route whose subtree runs server middleware asks the server first: the browser posts { "path": "/app/path", "search": "?x=1" } to POST…

For agentsUpdated

A client navigation into a route whose subtree runs server middleware asks the server first: the browser posts { "path": "/app/path", "search": "?x=1" } to POST {base}/_dusk/nav with the header x-dusk-navigation: check. The middleware of the target runs with:

  • event.url equal to the TARGET (path and search), not the /_dusk/nav request;
  • event.isNavigationCheck true (false for every document request).

A middleware can therefore redirect a blocked navigation the way it redirects a document request:

ts
if (event.isNavigationCheck || !isSignedIn(event)) {
  throw redirect(`/sign-in?redirect_url=${encodeURIComponent(`${event.url.pathname}${event.url.search}`)}`);
}

The client applies the answer with the same meaning as a document redirect:

  • a redirect inside the app is a router navigation that replaces the history entry of the blocked URL;
  • a redirect to another origin leaves the app (location.replace), and the navigation stays pending until the page leaves, so no error boundary flashes;
  • a refusal without a redirect shows the status in the route's error boundary, as a loader error does.

A search that is not a query (no leading ?, a fragment, a backslash, control characters) is a 400.