Why are rewrites not revalidated?
Answered
B33fb0n3 posted this in #help-forum
B33fb0n3OP
Hey, I am currently creating a multi tenant app with own pages and subdomains.
The host will be read and the request will be rewritten, so my app can render the correct stuff.
For example:
The client enter
then the request will be rewritten to
When I now try to revalidate
Why? How can I solve it?
-----------------------------
Here's a reproduction: https://github.com/B33fb0n3/revalidaterewrites
Or https://codesandbox.io/p/github/B33fb0n3/revalidaterewrites/main
1. Start the app
2. Navigate to /helpi
3. Navigate to /revalidate
4. Navigate to /helpi
-> you see, that the helpi isn't revalidated.
The host will be read and the request will be rewritten, so my app can render the correct stuff.
For example:
The client enter
https://hello.example.com/hello/world then the request will be rewritten to
https://example.com/viewpage/hello.example.com/hello/worldWhen I now try to revalidate
/viewpage/hello.example.com/hello/world to show the user new content, but the page isn't revalidated. Why? How can I solve it?
-----------------------------
Here's a reproduction: https://github.com/B33fb0n3/revalidaterewrites
Or https://codesandbox.io/p/github/B33fb0n3/revalidaterewrites/main
1. Start the app
2. Navigate to /helpi
3. Navigate to /revalidate
4. Navigate to /helpi
-> you see, that the helpi isn't revalidated.
103 Replies
B33fb0n3OP
bump
B33fb0n3OP
bump
Let me try to clone your repo and test it
@B33fb0n3 the code is working fine for me
@B33fb0n3 Hey, I am currently creating a multi tenant app with own pages and subdomains.
The host will be read and the request will be rewritten, so my app can render the correct stuff.
For example:
The client enter
https://hello.example.com/hello/world
then the request will be rewritten to https://example.com/viewpage/hello.example.com/hello/world
When I now try to revalidate /viewpage/hello.example.com/hello/world to show the user new content, but the page isn't revalidated.
Why? How can I solve it?
-----------------------------
Here's a reproduction: https://github.com/B33fb0n3/revalidaterewrites
Or https://codesandbox.io/p/github/B33fb0n3/revalidaterewrites/main
1. Start the app
2. Navigate to /helpi
3. Navigate to /revalidate
4. Navigate to /helpi
-> you see, that the helpi isn't revalidated.
in
/revalidate, you're revalidating /viewpage/somehost.com/helpi, not /helpi, and the desired path is getting revalidated@Anay-208 in `/revalidate`, you're revalidating `/viewpage/somehost.com/helpi`, not `/helpi`, and the desired path is getting revalidated
B33fb0n3OP
you are right. When revalidating
/helpi the page actually get's revalidated. But how to revalidate only the page "in the background", so the rewritten path?In this case it's a multi tenant app so I really want the host in the revalidation path. Else I would revalidate the path
/helpi for all tenants... and I don't want thatWhat do you think about that?
export const revalidate
@Anay-208 just set a revalidate time
B33fb0n3OP
that's possible. Imagine having 100.000 pages and every page will be revalidated every 30 minutes... I don't think that very effective. What do you think about it?
By that I mean, it'll revalidate only if you receive a request
B33fb0n3OP
exactly! And because of that I would like to use on demand revalidation only for the specific tenant (host) and only for the specific page (path)
@B33fb0n3 exactly! And because of that I would like to use on demand revalidation only for the specific tenant (host) and only for the specific page (path)
I'm not sure how you want it to work.
If you set up a
If you receive a request at 00:00, it'll fetch the latest, if you receive on 00:20, it'll return the cached, if you receive on 1:20, it'll then revalidate, and not before that.
If you set up a
revalidate path of 30 mins, its not that it'll revalidate every 30 mins.If you receive a request at 00:00, it'll fetch the latest, if you receive on 00:20, it'll return the cached, if you receive on 1:20, it'll then revalidate, and not before that.
it basically revalidates on request
@Anay-208 I'm not sure how you want it to work.
If you set up a `revalidate` path of 30 mins, its not that it'll revalidate every 30 mins.
If you receive a request at 00:00, it'll fetch the latest, if you receive on 00:20, it'll return the cached, if you receive on 1:20, it'll then revalidate, and not before that.
B33fb0n3OP
oh, I missed that... maybe I try a combination of revalidate after time and draftMode. Then my customer is able to see the direct change and on the other hand there are not that much revalidations..
@Anay-208 it basically revalidates on request
B33fb0n3OP
I think when a page don't change there is no need to revalidate. Imagine having 100 customers spread over the day, per day on my clients page, that don't change. For 30 min revalidation time there are nearly 50 unnecessary revalidations
Do you think there is a way to "on demand" revalidate a specific page in this use case?
When I publish the customer page on subdomain.domain.com and I revalidate
When I publish the customer page on subdomain.domain.com and I revalidate
/helpi is that restricted to only the subdomain? 🤔@B33fb0n3 Do you think there is a way to "on demand" revalidate a specific page in this use case?
When I publish the customer page on subdomain.domain.com and I revalidate /helpi is that restricted to only the subdomain? 🤔
The thing is there is no way for code to know if revaluation is needed. So I guess no
@Anay-208 The thing is there is no way for code to know if revaluation is needed. So I guess no
B33fb0n3OP
I will have a function that is called to execute the specific code. Like you saw in my reproduction the visit of the page
@B33fb0n3 I will have a function that is called to execute the specific code. Like you saw in my reproduction the *visit of the page*
Yes, use that GitHub repo, but give the api route a call when it is changed
@Anay-208 Yes, use that GitHub repo, but give the api route a call when it is changed
B33fb0n3OP
I can't quite follow you right now... what do you mean?
@B33fb0n3 I can't quite follow you right now... what do you mean?
You sent the link to that repo. Give the call to the api like /revalidate and the link
@Anay-208 You sent the link to that repo. Give the call to the api like /revalidate and the link
B33fb0n3OP
ah got it. I updated the github repo to the revalidation via an api. Still the same result... if you want me to update the codesandbox, let me know
I’ll check it out tomorrow
@B33fb0n3 ah got it. I updated the github repo to the revalidation via an api. Still the same result... if you want me to update the codesandbox, let me know
By same result, do you mean it revalidates all urls
@Anay-208 By same result, do you mean it revalidates all urls
B33fb0n3OP
Up to now, when I try to revalidate as you saw with
viewpage/... then there is no revalidation even if /helpi is rewritten to viewpage/...@B33fb0n3 its working for me
@Anay-208 Click to see attachment
B33fb0n3OP
thanks for trying this. The client that visits the website won't see the
viewpage/somehost.com/helpi. The client only see's https://somehost.com/helpi that is rewritten to https://myhost.com/viewpage/helpi@B33fb0n3 thanks for trying this. The client that visits the website won't see the viewpage/somehost.com/helpi. The client only see's https://somehost.com/helpi that is rewritten to https://myhost.com/viewpage/helpi
Just redirect to /viewpage/helpi then instead of rewriting
or wait let me find another solution
@Anay-208 Just redirect to /viewpage/helpi then instead of rewriting
B33fb0n3OP
You mean to redirect the end customer to https://myhost.com/viewpage/helpi? 🤔
oh wait let me find a solution
can I know where you're rewriting the page?
@Anay-208 oh wait let me find a solution
B33fb0n3OP
Maybe the flow is not that clear right now, so let me clarify it. Imagine 3 persons:
The
The
Maybe this makes more sense for you 🙂
My page at
Hoster: MeUser: My CustomerEnd Customer: The website user from UserUser bought a domain. For example example.com. I own the domain myhost.com. I deployed my project to myhost.com. On this page the saved User-Data will be requested and the page loads. The page itself won't change that much, but sometimes. The
End Customer visits now https://example.com/helpi. The End Customer want to stay and view the page of https://example.com/helpi. The User created a domain CNAME (the domain and path stays the same, but the End customer is on another website in the background). If an End Customer visits example.com with any path, he will be redirected to myhost.com with the requested path.myhost.com now renders the page. Keep in mind: for the End Customer it looks like he's on https://example.com/helpi, but in the background he's on https://myhost.com/viewpage/example.com/helpiThe
/viewpage/ has no auto revalidation. Only on demand revalidation. Now User change the data in the background, that is rendered on the page. If End Customer now visits the website, then he should see the new version (maybe after reload, because of the stale version). Maybe this makes more sense for you 🙂
My page at
myhost.com will now rewritte the@B33fb0n3 I don't think it'll work for your usecase. even if I change
rewrite to redirect, and if it revalidates somehost.com, someotherhost.com also gets revalidated@Anay-208 <@301376057326567425> I don't think it'll work for your usecase. even if I change `rewrite` to `redirect`, and if it revalidates `somehost.com`, `someotherhost.com` also gets revalidated
B33fb0n3OP
so both hosts get's revalidated when revalidating
viewpage/somehost.com/helpi once?Correct
@Anay-208 Correct
B33fb0n3OP
why, when the path is different:
viewpage/somehost.com/helpiviewpage/someotherhost.com/helpi@B33fb0n3 why, when the path is different:
viewpage/somehost.com/helpi
viewpage/someotherhost.com/helpi
Maybe because it’s the same file. For the sake of testing I’ve gone directly to the route /viewpage/somehost.com/helpi and someotherhost
@Anay-208 Maybe because it’s the same file. For the sake of testing I’ve gone directly to the route /viewpage/somehost.com/helpi and someotherhost
B33fb0n3OP
I thought that happends only when you revalidate like this:
viewpage/[host]/[[...path]]. What do you think?I’m not sure, but I can push the changes if you want to test it out for yourself
If you give me access to a branch
@Anay-208 I’m not sure, but I can push the changes if you want to test it out for yourself
B33fb0n3OP
you already forked and published it?
@B33fb0n3 you already forked and published it?
I didn’t fork it
I just cloned it
B33fb0n3OP
I disabled all protection rules for it. Try to push. Else you can publish your own version or [take a look at this](https://github.com/orgs/community/discussions/53358)
I'm facing some issues on github. Here are the changes:
//middleware.js
export function middleware(request) {
const { searchParams} = new URL(request.url)
let host = searchParams.get('host') ?? "somehost.com";
// host = "somehost.com";
console.log(host)
return NextResponse.redirect(new URL('/viewpage/' + host + request.nextUrl.pathname, request.url))
}//page.js
const hostKey = params.page[0];
const pagePath = params.page.slice(1, params.page.length).join("/");
console.log("page.js requested")
if(pagePath !== "helpi" || !(hostKey == "somehost.com" || hostKey == "someotherhost.com"))
return notFound() @Anay-208 I'm facing some issues on github. Here are the changes:
js
//middleware.js
export function middleware(request) {
const { searchParams} = new URL(request.url)
let host = searchParams.get('host') ?? "somehost.com";
// host = "somehost.com";
console.log(host)
return NextResponse.redirect(new URL('/viewpage/' + host + request.nextUrl.pathname, request.url))
}
js
//page.js
const hostKey = params.page[0];
const pagePath = params.page.slice(1, params.page.length).join("/");
console.log("page.js requested")
if(pagePath !== "helpi" || !(hostKey == "somehost.com" || hostKey == "someotherhost.com"))
return notFound()
B33fb0n3OP
Ah nice. Where is the part in which you load the different page data? Currently we only see the timestamp. But not to which page it's related to. Do you know what I mean?
@B33fb0n3 Ah nice. Where is the part in which you load the different page data? Currently we only see the timestamp. But not to which page it's related to. Do you know what I mean?
just go to
/viewpage/somehost.com/helpi and /viewpage/someotherhost.com/helpi, if you revalidate one, the other also gets revalidated@Anay-208 just go to `/viewpage/somehost.com/helpi` and `/viewpage/someotherhost.com/helpi`, if you revalidate one, the other also gets revalidated
B33fb0n3OP
Oh ok. How do I then create an on demand revalidation for this use case?
@B33fb0n3 I've got on demand cache working
@B33fb0n3 use unstable cache, and use
revalidateTagimport React from "react";
import { notFound } from "next/navigation";
import RevalidateButton from "@/app/viewpage/[[...page]]/components/RevalidateButton";
import { unstable_cache } from "next/cache";
export const dynamic = "force-static";
export default async function CustomerPage({ params }) {
const hostKey = params.page[0];
const pagePath = params.page.slice(1, params.page.length).join("/");
const getTime = unstable_cache(
async () => {
return await (
await fetch("https://worldtimeapi.org/api/timezone/America/Chicago")
).json();
},
[hostKey],
{ tags: [hostKey] }
);
if (
pagePath !== "helpi" ||
!(hostKey == "somehost.com" || hostKey == "someotherhost.com")
)
return notFound();
const data = await getTime();
// const result = await fetch('https://worldtimeapi.org/api/timezone/America/Chicago', {next: {tags: [hostKey]}});
// const data = await result.json();
return (
<>
<p>{data.datetime}</p>
<RevalidateButton />
</>
);
}and if you're usign revalidate, just add this in route.ts
import {revalidatePath, revalidateTag} from "next/cache";
import {NextResponse} from "next/server";
export async function POST() {
revalidateTag("somehost.com")
revalidatePath(`/helpi`)
return NextResponse.json({
now: Date.now(),
revalidated: true,
}, {status: 200})
}it'll revalidate the path, which is rewritten, and it'll get the cache from rewritten path
B33fb0n3OP
That seems like a possible solution even if it's a production env. and I should use unstable cache.. But I guess that's the only option here.
Do I really need to revalidate the path? Because when I revalidate
Do I really need to revalidate the path? Because when I revalidate
/helpi the page helpi get's revalidated for all hosts..@B33fb0n3 That seems like a possible solution even if it's a production env. and I should use unstable cache.. But I guess that's the only option here.
Do I really need to revalidate the path? Because when I revalidate /helpi the page helpi get's revalidated for *all hosts*..
Then other option is to redirect. It’s because of the fact that /helpi gets cached.
/helpi will rewrite, and the rewritten url will return the cached.
@B33fb0n3 if your issue is resolved,
Mark my message as a solution
Mark my message as a solution
@Anay-208 /helpi will rewrite, and the rewritten url will return the cached.
B33fb0n3OP
So I can't just revalidate only the tag?
If you use redirect. Then yes
@B33fb0n3
@Anay-208 If you use redirect. Then yes
B33fb0n3OP
else not? 🤔
@B33fb0n3 else not? 🤔
Nope, /helpi will need to be revalidated as /helpi is returning the cached data
@Anay-208 Nope, /helpi will need to be revalidated as /helpi is returning the cached data
B33fb0n3OP
hm ok. I will try it tomorrow. I will give you an update! ^^
@B33fb0n3 hm ok. I will try it tomorrow. I will give you an update! ^^
I’ll also create a pull request for you
@Anay-208 I’ll also create a pull request for you
B33fb0n3OP
yea please. I recently checked the nextjs template for plattforms and saw these interesting things:
1. [Revalidation](https://github.com/vercel/platforms/blob/main/lib/actions.ts#L251)
2. [Method to get data](https://github.com/vercel/platforms/blob/main/lib/fetchers.ts#L66C16-L66C30)
3. [Get actual data](https://github.com/vercel/platforms/blob/main/app/%5Bdomain%5D/%5Bslug%5D/page.tsx#L91)
4. [No revalidation settings](https://github.com/vercel/platforms/blob/main/app/%5Bdomain%5D/%5Bslug%5D/page.tsx#L8)
1. [Revalidation](https://github.com/vercel/platforms/blob/main/lib/actions.ts#L251)
2. [Method to get data](https://github.com/vercel/platforms/blob/main/lib/fetchers.ts#L66C16-L66C30)
3. [Get actual data](https://github.com/vercel/platforms/blob/main/app/%5Bdomain%5D/%5Bslug%5D/page.tsx#L91)
4. [No revalidation settings](https://github.com/vercel/platforms/blob/main/app/%5Bdomain%5D/%5Bslug%5D/page.tsx#L8)
@B33fb0n3 can you check
There's a known bug related to rewrites and revalidations
maybe it's your issue
normally you revalidate the path = what you have in Next
not sure about your exact context but if you have multiteancy you usually do smth like "domain.com" -> [domain]/page
you can revalidate a precise domain
but this bug may prevents this (it's a very annoying one to be honest)
@Eric Burel you can revalidate a precise domain
by that, if we mention the origin also like localhost:3000/helpi
@Anay-208 by that, if we mention the origin also like localhost:3000/helpi
normally rewrite should not have an impact
you invalidate a path
from the perspective of your Next.js app after the rewrite
but there is this infortunate bug that may add noise in Next 14, so sometimes your code is right but it's Next that's wrong, you might be in this scenario
@Eric Burel normally rewrite should not have an impact
and I actually thought that the url which was rewritten was cached. is that the case or is it a bug?
like /helpi was cached, which was rewritten
but if it shouldn't have an impact, then its a bug only
@B33fb0n3 done
Did it work?
@Eric Burel but there is this infortunate bug that may add noise in Next 14, so sometimes your code is right but it's Next that's wrong, you might be in this scenario
B33fb0n3OP
I think so too, that this is [the bug that you mentioned](https://nextjs-forum.com/post/1207313294990508042#message-1209085018089988097)
I recommend use redirect for now, once issue is fixed use write
@Anay-208 Did it work?
B33fb0n3OP
just tested it and yes, that works! Even without the revalidatePath ^^
So I guess I will just use the revalidateTag with the host. When removing the revalidatePath also only the specific page gets revalidated
So I guess I will just use the revalidateTag with the host. When removing the revalidatePath also only the specific page gets revalidated
B33fb0n3OP