0
Fork 0
mirror of https://github.com/withastro/astro.git synced 2025-01-06 22:10:10 -05:00
astro/.changeset/tall-waves-impress.md
Ben Holmes d10f91815e
Actions middleware (#12373)
* add manual middleware config option with getMiddlewareContext()

* refactor requestInfo to action object

* set action error response status from render context

* update automatic middleware to plain POST handler

* fix missing Locals type

* test: add separate POST and cookie forwarding tests

* remove actions.middleware flag

* add docs on actionResultAlreadySet

* test: use Astro.rewrite instead of middleware next(). TODO: fix next()

* fix type errors from rebase

* test: remove middleware handler

* test: use cookie forwarding for 'lots of fields'

* refactor: _isPrerendered -> ctx.isPrerendered

* expose getOriginPathname as middleware utility

* add support for handling RPC action results from middleware

* test: RPC security middleware

* refactor POST route handler to use getMiddlewareContext()

* remove unused actionRedirect flag

* changeset

* test: add expectedd rewrite failure for Ema to debug

* fix e2e test

* nit: form -> from

Co-authored-by: Emanuele Stoppa <my.burning@gmail.com>

* rename getMiddlewareContext -> getActionContext

* rename form-action -> form

* move /_actions/ route pattern to const

* move type defs to user-accessible ActionMiddlewareContext type

* export action middleware context type

* strip omitted fields for Action API Context

* add satisfies to type for good measure

* move getOriginPathname to shared ctx.originPathname

* remove `next()` rewrite because it isn't supported

* fix empty forms raising a 415

* fix missing async on cookie example

* nit: ctx -> context

* fix json parse error when content length is 0

* refactor body parsing to function

* edit: migration -> updating your HTML form actions

Co-authored-by: Sarah Rainsberger <sarah@rainsberger.ca>

* update changeset to match docs v5 guide

* add absolute urls to changeset links

---------

Co-authored-by: Emanuele Stoppa <my.burning@gmail.com>
Co-authored-by: Sarah Rainsberger <sarah@rainsberger.ca>
2024-11-08 17:03:57 -05:00

62 lines
2.7 KiB
Markdown

---
'astro': minor
---
Changes the default behavior for Astro Action form requests to a standard POST submission.
In Astro 4.x, actions called from an HTML form would trigger a redirect with the result forwarded using cookies. This caused issues for large form errors and return values that exceeded the 4 KB limit of cookie-based storage.
Astro 5.0 now renders the result of an action as a POST result without any forwarding. This will introduce a "confirm form resubmission?" dialog when a user attempts to refresh the page, though it no longer imposes a 4 KB limit on action return value.
## Customize form submission behavior
If you prefer to address the "confirm form resubmission?" dialog on refresh, or to preserve action results across sessions, you can now [customize action result handling from middleware](https://5-0-0-beta.docs.astro.build/en/guides/actions/#advanced-persist-action-results-with-a-session).
We recommend using a session storage provider [as described in our Netlify Blob example](https://5-0-0-beta.docs.astro.build/en/guides/actions/#advanced-persist-action-results-with-a-session). However, if you prefer the cookie forwarding behavior from 4.X and accept the 4 KB size limit, you can implement the pattern as shown in this sample snippet:
```ts
// src/middleware.ts
import { defineMiddleware } from 'astro:middleware';
import { getActionContext } from 'astro:actions';
export const onRequest = defineMiddleware(async (context, next) => {
// Skip requests for prerendered pages
if (context.isPrerendered) return next();
const { action, setActionResult, serializeActionResult } = getActionContext(context);
// If an action result was forwarded as a cookie, set the result
// to be accessible from `Astro.getActionResult()`
const payload = context.cookies.get('ACTION_PAYLOAD');
if (payload) {
const { actionName, actionResult } = payload.json();
setActionResult(actionName, actionResult);
context.cookies.delete('ACTION_PAYLOAD');
return next();
}
// If an action was called from an HTML form action,
// call the action handler and redirect with the result as a cookie.
if (action?.calledFrom === 'form') {
const actionResult = await action.handler();
context.cookies.set('ACTION_PAYLOAD', {
actionName: action.name,
actionResult: serializeActionResult(actionResult),
});
if (actionResult.error) {
// Redirect back to the previous page on error
const referer = context.request.headers.get('Referer');
if (!referer) {
throw new Error('Internal: Referer unexpectedly missing from Action POST request.');
}
return context.redirect(referer);
}
// Redirect to the destination page on success
return context.redirect(context.originPathname);
}
return next();
})
```