next-on-pages icon indicating copy to clipboard operation
next-on-pages copied to clipboard

[🐛 Bug]: Calling server actions on a static or SSR pages returns 405: Method Not Allowed

Open Maronato opened this issue 1 year ago • 17 comments

next-on-pages environment related information

System:
        Platform: darwin
        Arch: arm64
        Version: Darwin Kernel Version 23.2.0: Wed Nov 15 21:55:06 PST 2023; root:xnu-10002.61.3~2/RELEASE_ARM64_T6020
        CPU: (12) arm64 Apple M2 Max
        Memory: 64 GB
        Shell: /bin/zsh
Package Manager Used: npm (9.8.1)

Relevant Packages:
        @cloudflare/next-on-pages: 1.9.0
        vercel: 33.5.2
        next: 14.1.0

Description

Next allows server actions on static, SSR and edge routes. next-on-pages, however, doesn't seem to register POST routes if the page isn't using the edge runtime, causing them to return 405s.

Reproduction

Repo: https://github.com/Maronato/next-on-pages-server-actions-repro The files changed in the repo are src/action.ts and src/app/hello/page.tsx

Repo setup

  1. Clone it
  2. npm install

Desired behavior

  1. Run npm run dev (alternatively, npm run build, npm run start)
  2. Go to https://localhost:3000/hello
  3. Click the button and see that the request succeeds

Pages behavior

  1. npm run preview
  2. Go to https://localhost:3000/hello
  3. Click the button and see that the request fails

Pages Deployment Method

None

Pages Deployment ID

No response

Additional Information

No response

Would you like to help?

  • [ ] Would you like to help fixing this bug?

Maronato avatar Feb 26 '24 03:02 Maronato

Please can you try passing your server action from a server component to a child component as a prop, as a workaround?

james-elicx avatar Feb 26 '24 08:02 james-elicx

I updated the reproduction repo so src/app/hello/page.tsx is a server component and passes the action to the client component src/components/MyComponent.tsx.

It works fine in dev and with next start, but gives the same error with wrangler.

Maronato avatar Feb 26 '24 09:02 Maronato

I ran into the same issue. For now, I just moved from Cloudflare Pages to Vercel and that fixed it. I would love to move back when/if this gets resolved. I'm not a very good frontend developer, so I wanted to follow along with the latest Next.js docs / online content.

public-daniel avatar Feb 28 '24 04:02 public-daniel

Same issue here

karimkaylani avatar Feb 28 '24 10:02 karimkaylani

Yeah, I got same 405 on POST forms for Next-Auth V5beta (edge ready) or Iron-session v8 (edge ready). I try to debug but CF debuger only show the POST url causing the error, e.g: https://my-next-on-pages-app.pages.dev/auth/login Thus, I think that the POST method is limited somewhere.

TimKieu avatar Mar 14 '24 09:03 TimKieu

any updates on this? :/

fpunny avatar Mar 17 '24 08:03 fpunny

I haven't investigated it because I've been pretty busy, but my assuption would be if you're calling it from a prerendered/non-edge route, i would speculate that on Vercel they bypass the prerendered route and invoke the nodejs fallback function for action calls on static routes, which is not something we are able to do.

It's a theory that would make sense - how would you be able to call a server action if there is no function for it to invoke at that route? So, I would imagine that route's would need to use the edge runtime to call a server action, so that there is actually a function that it can run for your action call.

james-elicx avatar Mar 17 '24 14:03 james-elicx

For those coming from google. The "workaround" is to just make sure all pages are using edge with this line in your page.tsx.

export const runtime = 'edge';

ImLunaHey avatar Mar 24 '24 09:03 ImLunaHey

For those coming from google. The "workaround" is to just make sure all pages are using edge with this line in your page.tsx.


export const runtime = 'edge';

This is not good as the page counted as an edge function then you all pay for it like a worker request, which is not fairplay for web pages. I must give up all Nextjs ptojects and back to React to play with Cloudflare. Vercel can solve this but they are not CF.

TimKieu avatar Mar 24 '24 23:03 TimKieu

This is not good as the page counted as an edge function then you all pay for it like a worker request, which is not fairplay for web pages.

You pay for a worker request on requests to all routes with next-on-pages, because all requests to your routes go through our routing system in order to be correctly matched up to the page (whether prerendered or SSR'd).

I'm not sure I follow how you'd expect a server action to work when there's no edge function for the action to invoke?

james-elicx avatar Mar 25 '24 08:03 james-elicx

I also encountered this problem. I wrote export const runtime = 'edge'; in pages.tsx and it worked.

aigc-in-all avatar Aug 18 '24 07:08 aigc-in-all

Has there been any work on this issue?

ConnorBP avatar Jan 06 '25 17:01 ConnorBP

I'm not sure I follow how you'd expect a server action to work when there's no edge function for the action to invoke?

rendering page
______________
|            |
|  running   |
|   action   |
|            |
|____________|

Hey @james-elicx,

I wanted to clarify something about the action inside the static page. It's expected that the action should run in a worker, but it's not expected that rendering the page itself should happen in a worker just because it has an action inside it. The page might be a static page that's been compiled at build time.

The issue is that you can't signal next-on-pages to run the action in the edge runtime. You can't have export const runtime = 'edge'; in your actions file because files with "use server" can only export async functions, and 'edge' is a string, not an async function.

The only way to signal next-on-pages that your action should run in the edge runtime is to put export const runtime = 'edge'; in the page that has the call to that action. This has the side effect of making your static page a dynamic page that runs in a worker, which makes it slower and adds extra cost.

If you are ignoring this issue under the assumption that there is a workaround for it, please reconsider your position.

sassanh avatar Jan 21 '25 13:01 sassanh

The issue is that you can't signal next-on-pages to run the action in the edge runtime.

The issue is that Next.js does not support separating actions from pages, and next-on-pages does not support invoking a page's code for non-edge runtime pages.

james-elicx avatar Jan 21 '25 13:01 james-elicx

The issue is that Next.js does not support separating actions from pages, and next-on-pages does not support invoking a page's code for non-edge runtime pages.

I understand now. So, even on Vercel's infrastructure, it's not possible to have a static page that calls an action that runs on the edge runtime, right? If that's the case, we can open an issue upstream.

sassanh avatar Jan 21 '25 13:01 sassanh

The issue is that Next.js does not support separating actions from pages, and next-on-pages does not support invoking a page's code for non-edge runtime pages.

I understand now. So, even on Vercel's infrastructure, it's not possible to have a static page that calls an action that runs on the edge runtime, right? If that's the case, we can open an issue upstream.

On their infra, they are still able to invoke the Node.js-based ISR function for the static page, so it wouldn't be an issue over there.

I would recommend trying out OpenNext if you want to use Cloudflare going forward.

james-elicx avatar Jan 21 '25 14:01 james-elicx