Compare commits
3 commits
main
...
refactor-e
Author | SHA1 | Date | |
---|---|---|---|
|
5debbc74a1 | ||
|
e14e9dd1d9 | ||
|
d60c16a839 |
4 changed files with 115 additions and 118 deletions
|
@ -1,4 +1,3 @@
|
|||
import mime from 'mime';
|
||||
import type {
|
||||
EndpointHandler,
|
||||
ManifestData,
|
||||
|
@ -8,7 +7,7 @@ import type {
|
|||
SSRManifest,
|
||||
} from '../../@types/astro';
|
||||
import type { SinglePageBuiltModule } from '../build/types';
|
||||
import { attachToResponse, getSetCookiesFromResponse } from '../cookies/index.js';
|
||||
import { getSetCookiesFromResponse } from '../cookies/index.js';
|
||||
import { callEndpoint, createAPIContext } from '../endpoint/index.js';
|
||||
import { consoleLogDestination } from '../logger/console.js';
|
||||
import { error, type LogOptions } from '../logger/core.js';
|
||||
|
@ -44,7 +43,6 @@ export class App {
|
|||
#manifest: SSRManifest;
|
||||
#manifestData: ManifestData;
|
||||
#routeDataToRouteInfo: Map<RouteData, RouteInfo>;
|
||||
#encoder = new TextEncoder();
|
||||
#logging: LogOptions = {
|
||||
dest: consoleLogDestination,
|
||||
level: 'info',
|
||||
|
@ -299,36 +297,16 @@ export class App {
|
|||
mod: handler as any,
|
||||
});
|
||||
|
||||
const result = await callEndpoint(handler, this.#env, ctx, page.onRequest);
|
||||
const response = await callEndpoint(handler, this.#env, ctx, page.onRequest);
|
||||
|
||||
if (result.type === 'response') {
|
||||
if (result.response.headers.get('X-Astro-Response') === 'Not-Found') {
|
||||
if (response.headers.get('X-Astro-Response') === 'Not-Found') {
|
||||
const fourOhFourRequest = new Request(new URL('/404', request.url));
|
||||
const fourOhFourRouteData = this.match(fourOhFourRequest);
|
||||
if (fourOhFourRouteData) {
|
||||
return this.render(fourOhFourRequest, fourOhFourRouteData);
|
||||
}
|
||||
}
|
||||
return result.response;
|
||||
} else {
|
||||
const body = result.body;
|
||||
const headers = new Headers();
|
||||
const mimeType = mime.getType(url.pathname);
|
||||
if (mimeType) {
|
||||
headers.set('Content-Type', `${mimeType};charset=utf-8`);
|
||||
} else {
|
||||
headers.set('Content-Type', 'text/plain;charset=utf-8');
|
||||
}
|
||||
const bytes = this.#encoder.encode(body);
|
||||
headers.set('Content-Length', bytes.byteLength.toString());
|
||||
|
||||
const response = new Response(bytes, {
|
||||
status: 200,
|
||||
headers,
|
||||
});
|
||||
|
||||
attachToResponse(response, result.cookies);
|
||||
return response;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,6 @@ import type {
|
|||
AstroSettings,
|
||||
ComponentInstance,
|
||||
EndpointHandler,
|
||||
EndpointOutput,
|
||||
GetStaticPathsItem,
|
||||
ImageTransform,
|
||||
MiddlewareHandler,
|
||||
|
@ -556,18 +555,13 @@ async function generatePath(
|
|||
if (pageData.route.type === 'endpoint') {
|
||||
const endpointHandler = mod as unknown as EndpointHandler;
|
||||
|
||||
const result = await callEndpoint(
|
||||
endpointHandler,
|
||||
env,
|
||||
renderContext,
|
||||
onRequest as MiddlewareHandler<Response | EndpointOutput>
|
||||
);
|
||||
const result = await callEndpoint(endpointHandler, env, renderContext, onRequest, true);
|
||||
|
||||
if (result.type === 'response') {
|
||||
throwIfRedirectNotAllowed(result.response, opts.settings.config);
|
||||
if (result instanceof Response) {
|
||||
throwIfRedirectNotAllowed(result, opts.settings.config);
|
||||
// If there's no body, do nothing
|
||||
if (!result.response.body) return;
|
||||
const ab = await result.response.arrayBuffer();
|
||||
if (!result.body) return;
|
||||
const ab = await result.arrayBuffer();
|
||||
body = new Uint8Array(ab);
|
||||
} else {
|
||||
body = result.body;
|
||||
|
|
|
@ -9,6 +9,7 @@ import type {
|
|||
} from '../../@types/astro';
|
||||
import type { Environment, RenderContext } from '../render/index';
|
||||
|
||||
import mime from 'mime';
|
||||
import { isServerLikeOutput } from '../../prerender/utils.js';
|
||||
import { renderEndpoint } from '../../runtime/server/index.js';
|
||||
import { ASTRO_VERSION } from '../constants.js';
|
||||
|
@ -16,20 +17,16 @@ import { AstroCookies, attachToResponse } from '../cookies/index.js';
|
|||
import { AstroError, AstroErrorData } from '../errors/index.js';
|
||||
import { warn } from '../logger/core.js';
|
||||
import { callMiddleware } from '../middleware/callMiddleware.js';
|
||||
|
||||
const encoder = new TextEncoder();
|
||||
|
||||
const clientAddressSymbol = Symbol.for('astro.clientAddress');
|
||||
const clientLocalsSymbol = Symbol.for('astro.locals');
|
||||
|
||||
type EndpointCallResult =
|
||||
| {
|
||||
type: 'simple';
|
||||
type SimpleEndpointObject = {
|
||||
body: string;
|
||||
encoding?: BufferEncoding;
|
||||
cookies: AstroCookies;
|
||||
}
|
||||
| {
|
||||
type: 'response';
|
||||
response: Response;
|
||||
};
|
||||
};
|
||||
|
||||
type CreateAPIContext = {
|
||||
request: Request;
|
||||
|
@ -100,12 +97,29 @@ export function createAPIContext({
|
|||
return context;
|
||||
}
|
||||
|
||||
// Return response only
|
||||
export async function callEndpoint<MiddlewareResult = Response | EndpointOutput>(
|
||||
mod: EndpointHandler,
|
||||
env: Environment,
|
||||
ctx: RenderContext,
|
||||
onRequest?: MiddlewareHandler<MiddlewareResult> | undefined
|
||||
): Promise<EndpointCallResult> {
|
||||
): Promise<Response>;
|
||||
// Return response or a simple endpoint object (used for SSG)
|
||||
export async function callEndpoint<MiddlewareResult = Response | EndpointOutput>(
|
||||
mod: EndpointHandler,
|
||||
env: Environment,
|
||||
ctx: RenderContext,
|
||||
onRequest?: MiddlewareHandler<MiddlewareResult> | undefined,
|
||||
returnObjectFormIfAvailable?: boolean
|
||||
): Promise<Response | SimpleEndpointObject>;
|
||||
// Base implementation
|
||||
export async function callEndpoint<MiddlewareResult = Response | EndpointOutput>(
|
||||
mod: EndpointHandler,
|
||||
env: Environment,
|
||||
ctx: RenderContext,
|
||||
onRequest?: MiddlewareHandler<MiddlewareResult> | undefined,
|
||||
returnObjectFormIfAvailable?: boolean
|
||||
): Promise<Response | SimpleEndpointObject> {
|
||||
const context = createAPIContext({
|
||||
request: ctx.request,
|
||||
params: ctx.params,
|
||||
|
@ -128,14 +142,9 @@ export async function callEndpoint<MiddlewareResult = Response | EndpointOutput>
|
|||
response = await renderEndpoint(mod, context, env.ssr);
|
||||
}
|
||||
|
||||
if (response instanceof Response) {
|
||||
attachToResponse(response, context.cookies);
|
||||
return {
|
||||
type: 'response',
|
||||
response,
|
||||
};
|
||||
}
|
||||
|
||||
// If return simple endpoint object, convert to response
|
||||
if (!(response instanceof Response)) {
|
||||
// Validate properties not available in SSR
|
||||
if (env.ssr && !ctx.route?.prerender) {
|
||||
if (response.hasOwnProperty('headers')) {
|
||||
warn(
|
||||
|
@ -154,12 +163,50 @@ export async function callEndpoint<MiddlewareResult = Response | EndpointOutput>
|
|||
}
|
||||
}
|
||||
|
||||
// Passed during SSG where we don't need to return a full response, as we only need
|
||||
// to write the `body` to a file directly.
|
||||
if (returnObjectFormIfAvailable) {
|
||||
return {
|
||||
type: 'simple',
|
||||
body: response.body,
|
||||
encoding: response.encoding,
|
||||
cookies: context.cookies,
|
||||
};
|
||||
}
|
||||
|
||||
let body: BodyInit;
|
||||
const headers = new Headers();
|
||||
|
||||
const pathname = ctx.route
|
||||
? // Try the static route `pathname`
|
||||
ctx.route.pathname ??
|
||||
// Dynamic routes don't include `pathname`, so synthesize a path for these (e.g. 'src/pages/[slug].svg')
|
||||
ctx.route.segments.map((s) => s.map((p) => p.content).join('')).join('/')
|
||||
: // Fallback to pathname of the request
|
||||
ctx.pathname;
|
||||
const mimeType = mime.getType(pathname) || 'text/plain';
|
||||
headers.set('Content-Type', `${mimeType};charset=utf-8`);
|
||||
|
||||
if (typeof Buffer !== 'undefined' && Buffer.from) {
|
||||
body = Buffer.from(response.body, response.encoding);
|
||||
} else if (
|
||||
response.encoding == null ||
|
||||
response.encoding === 'utf8' ||
|
||||
response.encoding === 'utf-8'
|
||||
) {
|
||||
body = encoder.encode(response.body);
|
||||
headers.set('Content-Length', body.byteLength.toString());
|
||||
} else {
|
||||
body = response.body;
|
||||
}
|
||||
|
||||
response = new Response(body, {
|
||||
status: 200,
|
||||
headers,
|
||||
});
|
||||
}
|
||||
|
||||
attachToResponse(response, context.cookies);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
function isRedirect(statusCode: number) {
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
import type http from 'http';
|
||||
import mime from 'mime';
|
||||
import type { ComponentInstance, ManifestData, RouteData } from '../@types/astro';
|
||||
import { attachToResponse } from '../core/cookies/index.js';
|
||||
import { call as callEndpoint } from '../core/endpoint/dev/index.js';
|
||||
import { throwIfRedirectNotAllowed } from '../core/endpoint/index.js';
|
||||
import { AstroErrorData, isAstroError } from '../core/errors/index.js';
|
||||
|
@ -176,9 +174,8 @@ export async function handleRoute(
|
|||
}
|
||||
// Route successfully matched! Render it.
|
||||
if (route.type === 'endpoint') {
|
||||
const result = await callEndpoint(options);
|
||||
if (result.type === 'response') {
|
||||
if (result.response.headers.get('X-Astro-Response') === 'Not-Found') {
|
||||
const response = await callEndpoint(options);
|
||||
if (response.headers.get('X-Astro-Response') === 'Not-Found') {
|
||||
const fourOhFourRoute = await matchRoute('/404', env, manifest);
|
||||
return handleRoute(
|
||||
fourOhFourRoute,
|
||||
|
@ -192,27 +189,8 @@ export async function handleRoute(
|
|||
res
|
||||
);
|
||||
}
|
||||
throwIfRedirectNotAllowed(result.response, config);
|
||||
await writeWebResponse(res, result.response);
|
||||
} else {
|
||||
let contentType = 'text/plain';
|
||||
// Dynamic routes don't include `route.pathname`, so synthesize a path for these (e.g. 'src/pages/[slug].svg')
|
||||
const filepath =
|
||||
route.pathname ||
|
||||
route.segments.map((segment) => segment.map((p) => p.content).join('')).join('/');
|
||||
const computedMimeType = mime.getType(filepath);
|
||||
if (computedMimeType) {
|
||||
contentType = computedMimeType;
|
||||
}
|
||||
const response = new Response(Buffer.from(result.body, result.encoding), {
|
||||
status: 200,
|
||||
headers: {
|
||||
'Content-Type': `${contentType};charset=utf-8`,
|
||||
},
|
||||
});
|
||||
attachToResponse(response, result.cookies);
|
||||
throwIfRedirectNotAllowed(response, config);
|
||||
await writeWebResponse(res, response);
|
||||
}
|
||||
} else {
|
||||
const result = await renderPage(options);
|
||||
throwIfRedirectNotAllowed(result, config);
|
||||
|
|
Loading…
Reference in a new issue