Closed JBischoff28 closed 4 months ago
@JBischoff28 See here. The status code may be the reason for the redirection.
oh we can add a console warning or error in dev-only if the status codes aren't the redirecting kind
I can add more errors etc. but the issue is this line then
const url = new URL(href, 'http://localhost');
and how it's handled in makeQDataPath
function makeQDataPath(href: string) {
if (href.startsWith('/')) {
const append = QDATA_JSON;
const url = new URL(href, 'http://localhost');
const pathname = url.pathname.endsWith('/') ? url.pathname.slice(0, -1) : url.pathname;
return pathname + (append.startsWith('/') ? '' : '/') + append + url.search;
} else {
return undefined;
}
}
Thanks for the answer! The logs may indeed be unfriendly, as nothing is output when an unsuitable URL is specified as well as a status code.
And looking at it, it only allows redirecting to absolute paths in the same domain...
I'm currently trying to resolve this issue. For reference, I checked the redirect function in Next.js and it does indeed support external links.
I'm almost up to a simple implementation, but I still haven't figured out how to redirect externally in SSR context.
this is the nextjs redirect code https://github.com/vercel/next.js/blob/c26840909cf639aea181a01bb7b261bce43a5d22/packages/next/src/server/api-utils/index.ts#L59
/**
*
* @param res response object
* @param [statusOrUrl] `HTTP` status code of redirect
* @param url URL of redirect
*/
export function redirect(
res: NextApiResponse,
statusOrUrl: string | number,
url?: string
): NextApiResponse<any> {
if (typeof statusOrUrl === 'string') {
url = statusOrUrl
statusOrUrl = 307
}
if (typeof statusOrUrl !== 'number' || typeof url !== 'string') {
throw new Error(
`Invalid redirect arguments. Please use a single argument URL, e.g. res.redirect('/destination') or use a status code and URL, e.g. res.redirect(307, '/destination').`
)
}
res.writeHead(statusOrUrl, { Location: url })
res.write(url)
res.end()
return res
}
so this means in qwik we just don't care
requestEv.status(statusCode || 307);
requestEv.headers.set('Location', adaptedLocation);
requestEv.getWritableStream().close();
export async function handleRedirect(requestEv: RequestEvent) {
const isPageDataReq = requestEv.sharedMap.has(IsQData);
if (isPageDataReq) {
try {
await requestEv.next();
} catch (err) {
if (!(err instanceof RedirectMessage)) {
throw err;
}
}
if (requestEv.headersSent) {
return;
}
const status = requestEv.status();
const location = requestEv.headers.get('Location');
const isRedirect = status >= 301 && status <= 308 && location;
if (isRedirect) {
const adaptedLocation = makeQDataPath(location);
if (adaptedLocation) {
requestEv.headers.set('Location', adaptedLocation);
requestEv.getWritableStream().close();
return;
} else {
requestEv.status(200);
requestEv.headers.delete('Location');
}
}
}
}
update: ok actually the QDATA_JSON patch is probably needed
function makeQDataPath(href: string) {
if (href.startsWith('/')) {
const append = QDATA_JSON;
const url = new URL(href, 'http://localhost');
const pathname = url.pathname.endsWith('/') ? url.pathname.slice(0, -1) : url.pathname;
return pathname + (append.startsWith('/') ? '' : '/') + append + url.search;
} else {
return href;
}
}
I'm not sure of the edge cases here and why the code was added this way https://github.com/QwikDev/qwik/pull/2622/files
I tried a number of things with the Next.js code as a reference, but none of them worked.
requestEv.headers.set('Location', location);
requestEv.status(302);
requestEv.getWritableStream().close();
requestEv.redirect(302, location);
requestEv.getWritableStream().close();
None of these will simply work or will be blocked by CORS Policy on the browser. It is not clear why an error occurs on the browser side regarding redirects even though they are SSRs in the first place. Is it something to do with Qwik's Resumable?
@JerryWu1234 do you want to work on this one?
@JerryWu1234 do you want to work on this one?
please assign this to me
Create an empty route action and attach the route action to the Form's action prop. Try to redirect to another page using requestEvent.redirect
Could you give me a small reproduction to make sure I understand correctly?
@JBischoff28 @PatrickJS
production.tsx
import { component$ } from '@builder.io/qwik';
import { routeLoader$ } from '@builder.io/qwik-city';
export const useProductDetails = routeLoader$(async (requestEvent) => {
const product = {
name: 2222
}
console.log('Request headers:', requestEvent.request.headers);
console.log('Request cookies:', requestEvent.cookie);
console.log('Request url:', requestEvent.url);
console.log('Request method:', requestEvent.method);
console.log('Request params:', requestEvent.params);
requestEvent.redirect(302, 'http://localhost:5173')
return {
productName: product.name
};
});
export default component$(() => {
const product = useProductDetails();
return <div>Product name: {product.value.productName}</div>;
});
such as this ?
but I didn't capture this error
Nothing out of the ordinary. Use your standard development configs and you should get the same result.
I too have an issue with redirects. Here's qwik repro in Stackblitz: https://stackblitz.com/edit/qwik-redirects-er3vm8-36vtnr?file=src%2Froutes%2Flayout.tsx&view=editor (tested on v1.5.3 and v1.5.5)
To see this in action:
In my case I want to redirect to a page via URLSearchParams (add some filter params to url) to trigger routeLoader$
refetch and preserve filter parameters. Redirect triggers route loader, but the URL doesn't change, hence I can't preserve filter.
I also found out that if relative redirect URL doesn't start with /
then Qwik City will redirect to http://localhost
, which in case of StackBlitz means it redirects me to my local application (if I run one), or I just see error page.
From the network logs I can tell that I'm being redirected to /q-data.json?i=banana
(if I choose banana, for example), because this address is being sent via Location
header with 302 status code - the one I specified in redirect
call. I'm not sure what happens on Qwik's side, but shouldn't the Location
point to /?i=banana
instead? Or is this where the loader being called? Because I also see this URL in logs being requested just before redirect response with Location
set to this URL.
thank you for your demo, I'll check it late
When I disable JavaScript in my project redirects are working. But then I get unwanted qaction
attribute in address bar. So, I imagine Qwik performs SPA navigation. Am I right? Or rather, it just ignores server response with 3xx code and Location
header and just re-runs loaders.
I assume this is how actions performed on client side: https://github.com/QwikDev/qwik/blob/2da9d4b967ca5846b9a2a74b79c4ab0c2334b5a7/packages/qwik-city/runtime/src/use-endpoint.ts#L7-L84
And I don't see redirects being handled on client. According to MDN, fetch will follow redirects by default, meaning there will be a subsequent request to the address specified in Location
header. Because of this, loadClientData
function gets Response from that URL and Response.redirected
property set to true
, and I think redirects not being handled properly, so we don't have page the URL in address bar updated. Then if I disable JavaScript, the redirect is handled by browser automatically - following the response browser will send subsequent request to the URL from Location
header, as it should be. But with JS enabled, because our redirect is handled by fetch, we just get response from loader and then do nothing (at least this is what it looks like when I test this code). I hope this will help :)
I replaced isSamePathname
with isSamePath
here and it fixed my issue.
I fixed by another way. @octet-stream
Ok. I can't get e2e tests running anyway. With or without my solution.
Thankfully, pnpm has patch
command, so I can fix Qwik for my project while I wait for the fix :D
Which component is affected?
Qwik City (routing)
Describe the bug
I am trying to redirect from within a routeAction$. Instead of redirecting the user, nothing happens at all. Sometimes the redirect will work, other times it will not. There has not been an identifiable pattern either. The issue has occured with both absolute and relative url paths. I have tried changing the redirect's status code, but that also had no effect.
This issue has been persistent in every project that I've used Qwik, so it is not project specific. I have also reached out on discord, and was told it was not an issue that I am making.
The following is a message that was sent to me by a Qwik team member: ok looks to me that the makeQDataPath function isn't happy with your redirect URL. And looking at it, it only allows redirecting to absolute paths in the same domain... https://github.com/BuilderIO/qwik/blob/396e98ebab748109818f19523dc185d12bdb6aa1/packages/qwik-city/middleware/request-handler/resolve-request-handlers.ts#L546-L556
Reproduction
npm create qwik@latest
Steps to reproduce
System Info
Additional Information
No response