question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Unexpected behaviour when redirecting in action

See original GitHub issue

What version of Remix are you using?

1.4.1

Steps to Reproduce

Create a Remix project (with the built in Remix server) with the following routes:

index.tsx:

import { memo } from 'react'

const IndexRoute = memo(() => {
  return <h1>Home</h1>
})
IndexRoute.displayName = 'IndexRoute'

export default IndexRoute

magic-link.tsx:

import { memo, useEffect } from 'react'
import { LoaderFunction, json, useLoaderData, useSubmit } from 'remix'
import { emailFormFieldName, codeFormFieldName } from '~/routes/verify-magic-link'

type LoaderData = {
  email: string,
  code: string
}

const loader: LoaderFunction = async ({ request }) => {
  const url = new URL(request.url)
  const email = url.searchParams.get("email") ?? ''
  const code = url.searchParams.get("code") ?? ''

  return json<LoaderData>({
    email,
    code
  })
}

const MagicLinkRoute = memo(() => {
  const loaderData = useLoaderData<LoaderData>()
  const submit = useSubmit()

  useEffect(() => {
    const formData = new FormData()
    formData.append(emailFormFieldName, loaderData.email)
    formData.append(codeFormFieldName, loaderData.code)
    submit(formData, { method: 'post', action: '/verify-magic-link' })
  }, [loaderData.email, loaderData.code, submit])

  return (
    <p>Some pending UI</p>
  )
})
MagicLinkRoute.displayName = 'MagicLinkRoute'

export default MagicLinkRoute
export { loader }

verify-magic-link.tsx:

import { memo } from 'react'
import { ActionFunction, json, redirect, useActionData } from 'remix'

export const emailFormFieldName = 'email'
export const codeFormFieldName = 'code'

// fake verifyMagicLink function with forced failure
const verifyMagicLink = ({ email, code } : { email: string, code: string  }) => Promise.resolve(false)

type ActionData = Awaited<ReturnType<typeof verifyMagicLink>>

const action: ActionFunction = async ({ request }) => {
  const body = await request.formData()
  const email = body.get(emailFormFieldName)?.toString() ?? ''
  const code = body.get(codeFormFieldName)?.toString() ?? ''

  const verifyMagicLinkResult = await verifyMagicLink({ email, code })

  if (verifyMagicLinkResult === true) {
    return redirect('/')
  }

  return json<ActionData>(verifyMagicLinkResult)
}

const VerifyMagicLinkRoute = memo(() => {
  const actionData = useActionData<ActionData>()

  return (
    <p>{JSON.stringify(actionData, null, 2)}</p>
  )
})
VerifyMagicLinkRoute.displayName = 'VerifyMagicLinkRoute'

export default VerifyMagicLinkRoute
export { action }

In the entry.server.tsx handleRequest function put the following just before returning the response:

  console.log({
    type: 'handleRequest',
    url: request.url,
    method: request.method,
    response: newResponse.status
  })

In the entry.server.tsx handleDataRequest function put the following just before returning the response:

  console.log({
    type: 'handleDataRequest',
    url: request.url,
    method: request.method,
    response: newResponse.status
  })

Go to https://localhost:3000/magic-link?code=123456&email=test@test.com in your browser. In the terminal you should see:

{
  type: 'handleRequest',
  url: 'http://localhost:3000/magic-link?code=123456&email=test@test.com',
  method: 'GET',
  response: 200
}

{
  type: 'handleDataRequest',
  url: 'http://localhost:3000/verify-magic-link?_data=routes%2Fverify-magic-link',
  method: 'POST',
  response: 200
}

{
  type: 'handleDataRequest',
  url: 'http://localhost:3000/verify-magic-link?_data=root',
  method: 'GET',
  response: 200
}

This is what I would expect to see.

Now in verify-magic-link.tsx change const verifyMagicLink = ({ email, code } : { email: string, code: string }) => Promise.resolve(false) to const verifyMagicLink = ({ email, code } : { email: string, code: string }) => Promise.resolve(true).

Run the same request in your browser again.

Expected Behavior

Terminal should show:

{
  type: 'handleRequest',
  url: 'http://localhost:3000/magic-link?code=123456&email=test@test.com',
  method: 'GET',
  response: 200
}

{
  type: 'handleDataRequest',
  url: 'http://localhost:3000/verify-magic-link?_data=routes%2Fverify-magic-link',
  method: 'POST',
  response: 302
}

{
  type: 'handleDataRequest',
  url: 'http://localhost:3000/?_data=root',
  method: 'GET',
  response: 200
}

Actual Behavior

Terminal shows:

{
  type: 'handleRequest',
  url: 'http://localhost:3000/magic-link?code=123456&email=test@test.com',
  method: 'GET',
  response: 200
}

{
  type: 'handleDataRequest',
  url: 'http://localhost:3000/?_data=root',
  method: 'GET',
  response: 200
}

The POST request does not get logged by either handleRequest or handleDataRequest.

Even though I am taken to the index.tsx route as expected the 302 redirect response never seems to be returned to the browser. Instead when I look in the browser network tab I can see that the the response to the POST request was a 204 response.

This is causing me issues because I would like to add a set-cookie header on the redirect response but the cookie never gets set because the redirect response doesn’t make it to the browser.

Issue Analytics

  • State:open
  • Created a year ago
  • Comments:15

github_iconTop GitHub Comments

3reactions
danieltottcommented, Aug 31, 2022

@fknop I had the same issue - lots of weird things happening with LiveReload and remix-auth, especially re: redirecting when trying to log in. I verified that using the old version of LiveReload stops this problem from happening. Here’s the “custom” LiveReload function I’m using instead of the production one from remix (which is just the 1.6.4 version with no other changes):

export const LiveReload =
  process.env.NODE_ENV !== 'development'
    ? () => null
    : function LiveReload({
        port = Number(process.env.REMIX_DEV_SERVER_WS_PORT || 8002),
        nonce = undefined,
      }) {
        let js = String.raw;
        return (
          <script
            nonce={nonce}
            suppressHydrationWarning
            dangerouslySetInnerHTML={{
              __html: js`
              (() => {
                  let protocol = location.protocol === "https:" ? "wss:" : "ws:";
                  let host = location.hostname;
                  let socketPath = protocol + "//" + host + ":" + ${String(
                    port,
                  )} + "/socket";
                  let ws = new WebSocket(socketPath);
                  ws.onmessage = (message) => {
                    let event = JSON.parse(message.data);
                    if (event.type === "LOG") {
                      console.log(event.message);
                    }
                    if (event.type === "RELOAD") {
                      console.log("💿 Reloading window ...");
                      window.location.reload();
                    }
                  };

                  ws.onerror = (error) => {
                    console.log("Remix dev asset server web socket error:");
                    console.error(error);
                  };
                })();
              `,
            }}
          />
        );
      };
2reactions
OllyHodgsoncommented, Dec 1, 2022

I believe PR 4725 fixes this issue.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Testing action with redirect gives uexpectable behavior in yii2
So test fails due to this unexpected behavior. How to enforce application's redirects to work at the same entry point script?
Read more >
CSCvf99693 - ASA : WCCP redirect traffic is ... - Cisco Bug
Symptom: when using WCCP to redirect traffic from the ASA to the WSA, it is done through GRE tunnel. The router id of...
Read more >
The Ultimate Guide to Django Redirects - Real Python
In this detailed guide, you'll learn everything you need to know about HTTP redirects in Django. All the way from the low-level details...
Read more >
Redirect: The Surprising New Science of Psychological Change
What if there were a magic pill that could make you happier, turn you into a better parent, solve a number of your...
Read more >
Redirections in HTTP - MDN Web Docs - Mozilla
In HTTP, redirection is triggered by a server sending a special redirect response to a request. Redirect responses have status codes that start ......
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found