feat: Enhance proxy to forward client headers and control caching, and simplify video player's source handling by removing internal proxy URL construction.

This commit is contained in:
kuekhaoyang
2025-11-29 16:19:48 +08:00
parent a5c76b6f32
commit d7b2d373ea
4 changed files with 23 additions and 24 deletions
+11 -1
View File
@@ -15,7 +15,16 @@ export async function GET(request: NextRequest) {
}
try {
const response = await fetchWithRetry({ url, request });
// Extract headers to forward (Cookies, Accept-Language, etc.)
const requestHeaders: Record<string, string> = {};
const forwardHeaders = ['cookie', 'accept', 'accept-language'];
forwardHeaders.forEach(key => {
const value = request.headers.get(key);
if (value) requestHeaders[key] = value;
});
const response = await fetchWithRetry({ url, request, headers: requestHeaders });
const contentType = response.headers.get('Content-Type');
@@ -68,6 +77,7 @@ export async function GET(request: NextRequest) {
headers.set('Access-Control-Allow-Origin', '*');
headers.set('Access-Control-Allow-Methods', 'GET, OPTIONS');
headers.set('Access-Control-Allow-Headers', 'Content-Type, Authorization');
headers.set('Cache-Control', 'no-store, no-cache, must-revalidate, proxy-revalidate');
return new NextResponse(response.body, {
status: response.status,
+4 -10
View File
@@ -30,14 +30,8 @@ export function MobileVideoPlayer({
const { refs, state } = useMobilePlayerState();
const { currentTime } = state;
// Ensure src goes through proxy to avoid CORS/IP issues on Vercel
// But don't double-proxy if already proxied
const proxySrc = src.includes('/api/proxy')
? src
: `${typeof window !== 'undefined' ? window.location.origin : ''}/api/proxy?url=${encodeURIComponent(src)}`;
// Preload HLS segments
useHLSPreloader({ src: proxySrc, currentTime, videoRef: refs.videoRef, isLoading: state.isLoading });
useHLSPreloader({ src, currentTime, videoRef: refs.videoRef, isLoading: state.isLoading });
const {
videoRef,
@@ -60,7 +54,7 @@ export function MobileVideoPlayer({
} = state;
const logic = useMobilePlayerLogic({
src: proxySrc,
src,
initialTime,
shouldAutoPlay,
onError,
@@ -104,7 +98,7 @@ export function MobileVideoPlayer({
<video
ref={videoRef}
className="w-full h-full object-contain touch-none"
src={proxySrc}
src={src}
poster={poster}
onPlay={handlePlay}
onPause={handlePause}
@@ -133,7 +127,7 @@ export function MobileVideoPlayer({
/>
<MobileControlsWrapper
src={proxySrc}
src={src}
state={state}
logic={logic}
refs={refs}
+3 -8
View File
@@ -20,11 +20,6 @@ export function useHlsPlayer({
const video = videoRef.current;
if (!video || !src) return;
// Ensure src goes through proxy to avoid CORS/IP issues on Vercel
const proxySrc = src.includes('/api/proxy')
? src
: `${window.location.origin}/api/proxy?url=${encodeURIComponent(src)}`;
// Cleanup previous HLS instance
if (hlsRef.current) {
hlsRef.current.destroy();
@@ -54,7 +49,7 @@ export function useHlsPlayer({
});
hlsRef.current = hls;
hls.loadSource(proxySrc);
hls.loadSource(src);
hls.attachMedia(video);
hls.on(Hls.Events.MANIFEST_PARSED, () => {
@@ -122,12 +117,12 @@ export function useHlsPlayer({
} else {
console.log('[HLS] Using native HLS support');
// Native HLS support
video.src = proxySrc;
video.src = src;
}
} else if (isNativeHlsSupported) {
// Fallback for environments where Hls.js is not supported but native is (e.g. iOS without MSE?)
console.log('[HLS] Using native HLS support (Hls.js not supported)');
video.src = proxySrc;
video.src = src;
} else {
console.error('[HLS] HLS not supported in this browser');
}
+5 -5
View File
@@ -3,9 +3,10 @@ import { NextRequest } from 'next/server';
interface FetchWithRetryOptions {
url: string;
request: NextRequest;
headers?: Record<string, string>;
}
export async function fetchWithRetry({ url, request }: FetchWithRetryOptions): Promise<Response> {
export async function fetchWithRetry({ url, request, headers = {} }: FetchWithRetryOptions): Promise<Response> {
// User-Agent rotation for better compatibility
const userAgents = [
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
@@ -20,10 +21,8 @@ export async function fetchWithRetry({ url, request }: FetchWithRetryOptions): P
// Optional IP forwarding (default: Beijing IP)
const forwardedIP = request.nextUrl.searchParams.get('ip') || '202.108.22.5';
// Vercel serverless functions have a 10s default timeout
const isVercel = process.env.VERCEL === '1';
const MAX_RETRIES = isVercel ? 2 : 5;
const TIMEOUT_MS = isVercel ? 8000 : 30000; // 8s for Vercel, 30s for others
const MAX_RETRIES = 5;
const TIMEOUT_MS = 30000; // 30 seconds
let lastError: unknown = null;
let response: Response | null = null;
@@ -44,6 +43,7 @@ export async function fetchWithRetry({ url, request }: FetchWithRetryOptions): P
'X-Forwarded-For': forwardedIP,
'Client-IP': forwardedIP,
'Referer': referer,
...headers, // Merge custom headers (Cookie, Accept, etc.)
},
signal: controller.signal,
});