import type { NextRequest } from 'next/server'; import { getServerSideConfig } from '@/app/config/server'; import { NextResponse } from 'next/server'; export async function handle( req: NextRequest, { params }: { params: { path: string[] } }, ) { console.log('[Proxy Route] params ', params); if (req.method === 'OPTIONS') { return NextResponse.json({ body: 'OK' }, { status: 200 }); } const serverConfig = getServerSideConfig(); // remove path params from searchParams req.nextUrl.searchParams.delete('path'); req.nextUrl.searchParams.delete('provider'); const subpath = params.path.join('/'); const fetchUrl = `${req.headers.get( 'x-base-url', )}/${subpath}?${req.nextUrl.searchParams.toString()}`; const skipHeaders = ['connection', 'host', 'origin', 'referer', 'cookie']; const headers = new Headers( Array.from(req.headers.entries()).filter((item) => { if ( item[0].includes('x-') || item[0].includes('sec-') || skipHeaders.includes(item[0]) ) { return false; } return true; }), ); // if dalle3 use openai api key const baseUrl = req.headers.get('x-base-url'); if (baseUrl?.includes('api.openai.com')) { if (!serverConfig.apiKey) { return NextResponse.json( { error: 'OpenAI API key not configured' }, { status: 500 }, ); } headers.set('Authorization', `Bearer ${serverConfig.apiKey}`); } const controller = new AbortController(); const fetchOptions: RequestInit = { headers, method: req.method, body: req.body, // to fix #2485: https://stackoverflow.com/questions/55920957/cloudflare-worker-typeerror-one-time-use-body redirect: 'manual', // @ts-ignore duplex: 'half', signal: controller.signal, }; const timeoutId = setTimeout( () => { controller.abort(); }, 10 * 60 * 1000, ); try { const res = await fetch(fetchUrl, fetchOptions); // to prevent browser prompt for credentials const newHeaders = new Headers(res.headers); newHeaders.delete('www-authenticate'); // to disable nginx buffering newHeaders.set('X-Accel-Buffering', 'no'); // The latest version of the OpenAI API forced the content-encoding to be "br" in json response // So if the streaming is disabled, we need to remove the content-encoding header // Because Vercel uses gzip to compress the response, if we don't remove the content-encoding header // The browser will try to decode the response with brotli and fail newHeaders.delete('content-encoding'); return new Response(res.body, { status: res.status, statusText: res.statusText, headers: newHeaders, }); } finally { clearTimeout(timeoutId); } }