fix(frontend): upload asset lolos proxy — BODY_SIZE_LIMIT 8M + proxy 413 jelas
Body upload (JSON base64, ~7 MiB untuk file 5 MiB) ditolak default adapter-node 512K sebelum sampai backend Flask, lalu error itu terlapor sebagai 502 'Backend tidak tersedia'. - podman-compose: BODY_SIZE_LIMIT=8M untuk elemes-frontend - hooks.server: SvelteKitError body-size (413) dipisah dari kegagalan koneksi — balas 413 'Ukuran file terlalu besar' bukan 502 - test: proxy balas 413 untuk body melebihi limit
This commit is contained in:
parent
c127309dd8
commit
8fd39d6e1a
|
|
@ -57,6 +57,39 @@ describe('hooks.server handle', () => {
|
||||||
expect(response.headers.get('Cross-Origin-Resource-Policy')).toBe('cross-origin');
|
expect(response.headers.get('Cross-Origin-Resource-Policy')).toBe('cross-origin');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should return 413 with size message when body exceeds adapter limit', async () => {
|
||||||
|
// SvelteKitError dari adapter-node saat body POST melebihi BODY_SIZE_LIMIT.
|
||||||
|
// Proxy harus balas 413 dengan pesan ukuran — bukan 502 "Backend tidak tersedia".
|
||||||
|
const arrayBufferMock = vi.fn().mockRejectedValue(
|
||||||
|
Object.assign(new Error('Content-length of 947488 exceeds limit of 524288 bytes.'), { status: 413 })
|
||||||
|
);
|
||||||
|
const mockEvent: any = {
|
||||||
|
request: {
|
||||||
|
method: 'POST',
|
||||||
|
headers: new Headers({ 'content-type': 'application/json' }),
|
||||||
|
arrayBuffer: arrayBufferMock
|
||||||
|
},
|
||||||
|
url: new URL('https://sinau-c-dev.manakin-gentoo.ts.net/api/content/assets/upload')
|
||||||
|
};
|
||||||
|
|
||||||
|
const origFetch = global.fetch;
|
||||||
|
global.fetch = vi.fn() as any;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const resolve = vi.fn();
|
||||||
|
const response = await handle({ event: mockEvent, resolve });
|
||||||
|
|
||||||
|
expect(response.status).toBe(413);
|
||||||
|
const body = await response.json();
|
||||||
|
expect(body.success).toBe(false);
|
||||||
|
expect(body.message).toMatch(/terlalu besar/i);
|
||||||
|
// Tidak boleh dikirim ke backend sama sekali
|
||||||
|
expect(global.fetch).not.toHaveBeenCalled();
|
||||||
|
} finally {
|
||||||
|
global.fetch = origFetch;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
it('should read body as arrayBuffer when proxying POST requests', async () => {
|
it('should read body as arrayBuffer when proxying POST requests', async () => {
|
||||||
const arrayBufferMock = vi.fn().mockResolvedValue(new Uint8Array([1, 2, 3]).buffer);
|
const arrayBufferMock = vi.fn().mockResolvedValue(new Uint8Array([1, 2, 3]).buffer);
|
||||||
const mockEvent: any = {
|
const mockEvent: any = {
|
||||||
|
|
|
||||||
|
|
@ -77,9 +77,28 @@ export const handle: Handle = async ({ event, resolve }) => {
|
||||||
status: res.status,
|
status: res.status,
|
||||||
headers: resHeaders,
|
headers: resHeaders,
|
||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
|
// adapter-node melempar SvelteKitError saat body POST melebihi
|
||||||
|
// BODY_SIZE_LIMIT — bukan berarti backend mati. Laporkan sebagai 413
|
||||||
|
// dengan pesan yang jelas, jangan 502 "Backend tidak tersedia".
|
||||||
|
const isBodyTooLarge =
|
||||||
|
err?.status === 413 || /exceeds limit/i.test(String(err?.message ?? ''));
|
||||||
|
if (isBodyTooLarge) {
|
||||||
|
console.warn(`[hooks] Body too large for ${event.request.method} ${event.url.pathname}`);
|
||||||
|
return new Response(
|
||||||
|
JSON.stringify({
|
||||||
|
success: false,
|
||||||
|
error: 'Payload too large',
|
||||||
|
message: 'Ukuran file terlalu besar (maksimum 5 MiB per asset)'
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
status: 413,
|
||||||
|
headers: { 'content-type': 'application/json' }
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
console.error(`API proxy error (${backendUrl}):`, err);
|
console.error(`API proxy error (${backendUrl}):`, err);
|
||||||
return new Response(JSON.stringify({ error: 'Backend unavailable' }), {
|
return new Response(JSON.stringify({ success: false, error: 'Backend unavailable', message: 'Backend tidak tersedia' }), {
|
||||||
status: 502,
|
status: 502,
|
||||||
headers: { 'content-type': 'application/json' },
|
headers: { 'content-type': 'application/json' },
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -83,6 +83,9 @@ services:
|
||||||
environment:
|
environment:
|
||||||
- ORIGIN=${ORIGIN:-http://localhost:3000}
|
- ORIGIN=${ORIGIN:-http://localhost:3000}
|
||||||
- API_BACKEND=http://127.0.0.1:5000
|
- API_BACKEND=http://127.0.0.1:5000
|
||||||
|
# Backend menerima asset ≤ 5 MiB (JSON base64 ≈ 7 MiB di wire).
|
||||||
|
# Default adapter-node 512K menolak upload gambar sebelum sampai backend.
|
||||||
|
- BODY_SIZE_LIMIT=8M
|
||||||
- PUBLIC_APP_BAR_TITLE=${APP_BAR_TITLE}
|
- PUBLIC_APP_BAR_TITLE=${APP_BAR_TITLE}
|
||||||
- PUBLIC_COPYRIGHT_TEXT=${COPYRIGHT_TEXT}
|
- PUBLIC_COPYRIGHT_TEXT=${COPYRIGHT_TEXT}
|
||||||
- PUBLIC_PAGE_TITLE_SUFFIX=${PAGE_TITLE_SUFFIX}
|
- PUBLIC_PAGE_TITLE_SUFFIX=${PAGE_TITLE_SUFFIX}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue