mirror of
https://github.com/withastro/astro.git
synced 2025-02-03 22:29:08 -05:00
fix: handle immutable response object (#12106)
* fix: handle immutable response object * changeset
This commit is contained in:
parent
fbe1bc51d8
commit
d3a74da196
4 changed files with 36 additions and 12 deletions
5
.changeset/poor-doors-listen.md
Normal file
5
.changeset/poor-doors-listen.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
'astro': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Handles case where an immutable Response object is returned from an endpoint
|
|
@ -50,7 +50,7 @@ export async function renderEndpoint(
|
||||||
return new Response(null, { status: 500 });
|
return new Response(null, { status: 500 });
|
||||||
}
|
}
|
||||||
|
|
||||||
const response = await handler.call(mod, context);
|
let response = await handler.call(mod, context);
|
||||||
|
|
||||||
if (!response || response instanceof Response === false) {
|
if (!response || response instanceof Response === false) {
|
||||||
throw new AstroError(EndpointDidNotReturnAResponse);
|
throw new AstroError(EndpointDidNotReturnAResponse);
|
||||||
|
@ -59,10 +59,20 @@ export async function renderEndpoint(
|
||||||
// Endpoints explicitly returning 404 or 500 response status should
|
// Endpoints explicitly returning 404 or 500 response status should
|
||||||
// NOT be subject to rerouting to 404.astro or 500.astro.
|
// NOT be subject to rerouting to 404.astro or 500.astro.
|
||||||
if (REROUTABLE_STATUS_CODES.includes(response.status)) {
|
if (REROUTABLE_STATUS_CODES.includes(response.status)) {
|
||||||
// Only `Response.redirect` headers are immutable, therefore a `try..catch` is not necessary.
|
try {
|
||||||
// Note: `Response.redirect` can only be called with HTTP status codes: 301, 302, 303, 307, 308.
|
response.headers.set(REROUTE_DIRECTIVE_HEADER, 'no');
|
||||||
// Source: https://developer.mozilla.org/en-US/docs/Web/API/Response/redirect_static#parameters
|
} catch (err) {
|
||||||
response.headers.set(REROUTE_DIRECTIVE_HEADER, 'no');
|
// In some cases the response may have immutable headers
|
||||||
|
// This is the case if, for example, the user directly returns a `fetch` response
|
||||||
|
// There's no clean way to check if the headers are immutable, so we just catch the error
|
||||||
|
// Note that response.clone() still has immutable headers!
|
||||||
|
if((err as Error).message?.includes('immutable')) {
|
||||||
|
response = new Response(response.body, response);
|
||||||
|
response.headers.set(REROUTE_DIRECTIVE_HEADER, 'no');
|
||||||
|
} else {
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
|
|
3
packages/astro/test/fixtures/ssr-api-route/src/pages/fail.js
vendored
Normal file
3
packages/astro/test/fixtures/ssr-api-route/src/pages/fail.js
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
export async function GET({ request }) {
|
||||||
|
return fetch("https://http.im/status/500", request)
|
||||||
|
}
|
|
@ -137,23 +137,29 @@ describe('API routes in SSR', () => {
|
||||||
assert.equal(count, 2, 'Found two separate set-cookie response headers');
|
assert.equal(count, 2, 'Found two separate set-cookie response headers');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('can return an immutable response object', async () => {
|
||||||
|
const response = await fixture.fetch('/fail');
|
||||||
|
const text = await response.text();
|
||||||
|
assert.equal(response.status, 500);
|
||||||
|
assert.equal(text, '');
|
||||||
|
});
|
||||||
|
|
||||||
it('Has valid api context', async () => {
|
it('Has valid api context', async () => {
|
||||||
const response = await fixture.fetch('/context/any');
|
const response = await fixture.fetch('/context/any');
|
||||||
assert.equal(response.status, 200);
|
assert.equal(response.status, 200);
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
assert.equal(data.cookiesExist, true);
|
assert.ok(data.cookiesExist);
|
||||||
assert.equal(data.requestExist, true);
|
assert.ok(data.requestExist);
|
||||||
assert.equal(data.redirectExist, true);
|
assert.ok(data.redirectExist);
|
||||||
assert.equal(data.propsExist, true);
|
assert.ok(data.propsExist);
|
||||||
assert.deepEqual(data.params, { param: 'any' });
|
assert.deepEqual(data.params, { param: 'any' });
|
||||||
assert.match(data.generator, /^Astro v/);
|
assert.match(data.generator, /^Astro v/);
|
||||||
assert.equal(
|
assert.ok(
|
||||||
['http://[::1]:4321/blog/context/any', 'http://127.0.0.1:4321/blog/context/any'].includes(
|
['http://[::1]:4321/blog/context/any', 'http://127.0.0.1:4321/blog/context/any'].includes(
|
||||||
data.url,
|
data.url,
|
||||||
),
|
),
|
||||||
true,
|
|
||||||
);
|
);
|
||||||
assert.equal(['::1', '127.0.0.1'].includes(data.clientAddress), true);
|
assert.ok(['::1', '127.0.0.1'].includes(data.clientAddress));
|
||||||
assert.equal(data.site, 'https://mysite.dev/subsite/');
|
assert.equal(data.site, 'https://mysite.dev/subsite/');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Add table
Reference in a new issue