next-runtime
next-runtime copied to clipboard
Support 3rd party redirects
For things like billing flows, its not uncommon to want to redirect-after-POST to a 3rd party endpoint. next-runtime doesn't appear to support returning external URLs with its redirect handler.
I've even tried things like the following:
res.setHeader("location", someExternalURL);
res.statusCode = 307;
res.end();
return;
But I get this error:
error - Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
Right now, our workaround is to return json and update window.location.href during render. It'd be a little neater if this scenario could be detected and managed automatically.
Are you sure it's a next-runtime thing, that's bugging? I'm able to redirect to my own site without trouble:
https://codesandbox.io/s/next-runtime-cookie-forked-ko4iob?file=/pages/index.js
https://user-images.githubusercontent.com/1196524/159327690-a7967632-4f41-4954-ab8f-535b5c415034.mov
What about with the form hook?
Got it! Yeah, that's a bug that needs to get squashed. Thanks!
Ok, so when I'm trying to redirect using Form, it does work, but only if the receiving endpoint has CORS properly configured.
This works:
export const getServerSideProps = handle<PageProps>({
async get() {
return json({});
},
async post() {
return redirect('https://swapi.dev/api/people/1/');
},
});
export default function FormWithRemoteRedirect() {
return (
<Form method="post">
<button id="submit" type="submit">
Submit
</button>
</Form>
);
}
Replace the destination with https://meijer.ws, and it does not.
The problem is that the fetch request already handles the redirect. If that causes an error, such as 'NO CORS POLICY', the browser redirect won't be reached.
So we need to find a way to take over the redirect, and handle it manually. Good thing, fetch has an option for that:
return fetch(url.toString(), {
method,
headers: { accept: 'application/json' },
body: data,
+ redirect: 'manual',
});
Bad thing, when using redirect: manual, the response will get a type: "opaqueredirect" property, but (Location) headers won't be available. So, I'm leaning to supporting a "manual" redirect. Something like (pseudo):
<Form
action="/"
method="post"
redirect="manual"
onSuccess={() => window.location = 'https://remote'}
/>
That is unless we can find a way to catch the fetch error and determine that it was a failed redirect. To simplify the API we could also make it like:
<Form
action="/"
method="post"
redirect="https://remote"
/>
FWIW, for my current use case, we don't know the URL up front, we call the 3rd party in the post handler and it gives us back the URL to redirect to.
Will it still happen even if we use standard Next.js object with this shape?
{
redirect: {
destination: "/sign",
permanent: false,
},
}
See https://nextjs.org/docs/api-reference/data-fetching/get-server-side-props#redirect