-
-
Notifications
You must be signed in to change notification settings - Fork 3k
Description
Astro Info
Astro v5.14.3
Vite v6.3.6
Node v24.5.0
System macOS (arm64)
Package Manager npm
Output static
Adapter none
Integrations @astrojs/sitemap (v3.6.0)
If this issue only occurs in one browser, which browser is a problem?
No response
Describe the Bug
I am using astro as SSG for development only. My deployed stack neither runs node nor astro, it just serves the pages generated via astro during development using custom router and serving logic. The deployed page serving logic mainly consists in the mapping of a URL path string to the serving of a specific html file.
To be able to use astro as seamlessly as possibly during development, I've coded a middleware.js which aims to mimic the routing and serving behaviour of my deployed stack in local development mode via astro dev.
Now imagine that you have to do something based on the query string provided along with the page request in the middleware, before serving the page. E.g. if an incoming page request in astro dev mode is for /path/to/example?hello=world, I rewrite that request to src/pages/de/beispiel.astro, but before serving the src/pages/de/beispiel.astro page, I want to do something in the middleware based on the value of the hello query param.
With the middleware.js below (see it in action in linked stackblitz example):
import {
defineMiddleware,
sequence
} from "astro/middleware";
import {middleware} from "astro:i18n";
import {ENV} from "astro:env/client";
export const codicsRoutingMiddleware = defineMiddleware(
async (
ctx,
next
) => {
const response = await next();
// To only enable this in astro dev mode, middleware shall not be used during anything else / build
if (ENV === "dev") {
const requestedPath = ctx.url.pathname;
/**
* This is the routing logic (get to path to the existing astro page for the request path)
* Just like the router in deployed stack maps a request path to a html file.
*/
if (!ctx.isPrerendered) {
// Make sure that ctx.url.search is `?hello=world`
console.log(ctx.url.search);
if (requestedPath === `/path/to/example`) {
return ctx.rewrite(`/de/beispiel/${ctx.url.search}`);
}
} else {
/**
* This is the serving logic (serve the existing astro page, like serving the existing html page in prod)
*/
if (requestedPath === '/de/beispiel/') {
const html = await response.text();
// DO SOMETHING BASED ON QUERY PARAMS
// ctx.url.search is ALWAYS EMPTY
return new Response(
html.replaceAll(
"</body>",
`${someMarkup}</body>`
),
{
status: 200,
headers: response.headers
}
);
}
}
}
return response;
}
);
export const onRequest = sequence(
codicsRoutingMiddleware,
middleware(
{
prefixDefaultLocale: true,
redirectToDefaultLocale: true,
}
)
)
With that middleware, when reaching my page, the query string is available in my beispiel.astro script, but it is never avilable within the middleware.js itself.
return ctx.rewrite(/de/beispiel/?hello=world);
... it simply never works.
As a workaround to this, I have defined a singleton helper class e.g.:
class QueryParamsStorageToSurviveDevRewrite {
static #instance;
static instance() {
if (QueryParamsStorageToSurviveDevRewrite.#instance === undefined) {
QueryParamsStorageToSurviveDevRewrite.#instance = new QueryParamsStorageToSurviveDevRewrite();
}
return QueryParamsStorageToSurviveDevRewrite.#instance;
}
#queryStringOfLastRequest = '';
/**
* To always set the value in a standardized way
*/
static setQueryStringOfLastRequest(searchString) {
QueryParamsStorageToSurviveDevRewrite.instance().#queryStringOfLastRequest = searchString.startsWith('?')
? searchString.substring(1)
: searchString;
}
/**
* Make sure that the value is reset each time it is read
* @returns {string}
*/
static getQueryStringOfLastRequest() {
const currentValue = QueryParamsStorageToSurviveDevRewrite.instance().#queryStringOfLastRequest;
QueryParamsStorageToSurviveDevRewrite.instance().#queryStringOfLastRequest = '';
return currentValue;
}
}
export {QueryParamsStorageToSurviveDevRewrite}
Then, I adapt my middleware slightly, to:
[...]
if (!ctx.isPrerendered) {
QueryParamsStorageToSurviveDevRewrite.setQueryStringOfLastRequest(ctx.url.search);
[...]
} else {
if (requestedPath === '/de/beispiel/') {
// Act based on QueryParamsStorageToSurviveDevRewrite.getQueryStringOfLastRequest()
[...]
This makes the query string of the last request available in the middleware, but all of this feels like a bug?
Some of the below point into the same direction :
- QueryParams are stripped #4399
- fix(routing): compute
APIContext.paramswhen rewriting usingnext#12031 - Astro.params not properly set when rewriting in middleware #11932
But I feel that my issue is something different?
What's the expected result?
When a rewrite is performed with an explicitly provided query string, the query string should be preserved and survive the rewrite, not only for the end file, but also within the middleware.js itself.
Link to Minimal Reproducible Example
https://stackblitz.com/edit/github-oiiafger?file=src%2Fmiddleware.js
Participation
- I am willing to submit a pull request for this issue.