© {new Date().getFullYear()} {siteConfig.title}
diff --git a/frontend/src/pages/admin/editor.astro b/frontend/src/pages/admin/editor.astro
index ce50b94..ea2a6dc 100644
--- a/frontend/src/pages/admin/editor.astro
+++ b/frontend/src/pages/admin/editor.astro
@@ -327,7 +327,7 @@ import Layout from '../../layouts/Layout.astro';
delBtn?.addEventListener('click', async () => {
if (confirm(`Delete post "${slugInput.value}" permanently?`)) {
try {
- const res = await fetch(`/api/posts/${slugInput.value}`, {
+ const res = await fetch(`/api/posts/${encodeURIComponent(slugInput.value)}`, {
method: 'DELETE',
headers: { 'Authorization': `Bearer ${token}` }
});
diff --git a/frontend/src/pages/admin/index.astro b/frontend/src/pages/admin/index.astro
index 578076d..b4fa384 100644
--- a/frontend/src/pages/admin/index.astro
+++ b/frontend/src/pages/admin/index.astro
@@ -106,7 +106,7 @@ import Layout from '../../layouts/Layout.astro';
const slug = (e.currentTarget as HTMLElement).dataset.slug;
if (confirm(`Are you sure you want to delete "${slug}"?`)) {
try {
- const delRes = await fetch(`/api/posts/${slug}`, {
+ const delRes = await fetch(`/api/posts/${encodeURIComponent(slug)}`, {
method: 'DELETE',
headers: { 'Authorization': `Bearer ${token}` }
});
diff --git a/frontend/src/pages/api/[...path].ts b/frontend/src/pages/api/[...path].ts
index b9c1744..ef54a0f 100644
--- a/frontend/src/pages/api/[...path].ts
+++ b/frontend/src/pages/api/[...path].ts
@@ -8,13 +8,14 @@ export const ALL: APIRoute = async ({ request, params }) => {
return new Response(JSON.stringify({ error: 'Missing path' }), { status: 400 });
}
+ // Ensure path is properly encoded
const url = new URL(`${API_URL}/api/${path}`);
const requestUrl = new URL(request.url);
url.search = requestUrl.search;
- // Filter headers to avoid conflicts with the backend container
const headers = new Headers();
- const forbiddenHeaders = ['host', 'connection', 'origin', 'referer', 'content-length'];
+ // Filter headers to avoid conflicts. Content-Type is handled automatically for POST/PUT if we pass arrayBuffer.
+ const forbiddenHeaders = ['host', 'connection', 'origin', 'referer', 'content-length', 'transfer-encoding'];
request.headers.forEach((value, key) => {
if (!forbiddenHeaders.includes(key.toLowerCase())) {
@@ -23,16 +24,23 @@ export const ALL: APIRoute = async ({ request, params }) => {
});
try {
+ console.log(`[Proxy] ${request.method} ${requestUrl.pathname} -> ${url.toString()}`);
+
+ let body: any = undefined;
+ if (request.method !== 'GET' && request.method !== 'HEAD') {
+ body = await request.arrayBuffer();
+ }
+
const response = await fetch(url.toString(), {
method: request.method,
headers: headers,
- // Pass the body stream directly for efficiency
- body: request.method !== 'GET' && request.method !== 'HEAD' ? request.body : undefined,
- // @ts-ignore - duplex is required for streaming bodies in some fetch implementations
+ body: body,
+ // @ts-ignore
duplex: 'half'
});
- // Extract headers for the response
+ console.log(`[Proxy] Backend returned ${response.status} for ${url.toString()}`);
+
const responseHeaders = new Headers();
response.headers.forEach((value, key) => {
responseHeaders.set(key, value);
diff --git a/frontend/src/pages/index.astro b/frontend/src/pages/index.astro
index ff34cd4..5961e91 100644
--- a/frontend/src/pages/index.astro
+++ b/frontend/src/pages/index.astro
@@ -43,7 +43,7 @@ function formatSlug(slug: string) {
-