From 4d71f39ee92548b3e37aea92f435071bf52707f6 Mon Sep 17 00:00:00 2001 From: Developer Date: Tue, 10 Mar 2026 20:47:14 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20proxy=20B=E7=AB=99=E5=9B=BE=E7=89=87=20C?= =?UTF-8?q?DN=20=E8=A7=A3=E5=86=B3=20web=20=E7=AB=AF=E9=98=B2=E7=9B=97?= =?UTF-8?q?=E9=93=BE=E5=9B=BE=E7=89=87=E4=B8=8D=E6=98=BE=E7=A4=BA=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - dev-proxy.js 新增 /bilibili-img 路由,代理 *.hdslb.com 并注入正确 Referer - utils/imageUrl.ts 新增 proxyImageUrl(),web 端将图片 URL 转为本地代理地址 - VideoCard / CommentItem / MiniPlayer / [bvid] 对所有 B站图片应用 proxyImageUrl --- app/video/[bvid].tsx | 3 ++- components/CommentItem.tsx | 3 ++- components/MiniPlayer.tsx | 3 ++- components/VideoCard.tsx | 3 ++- dev-proxy.js | 9 +++++++++ utils/imageUrl.ts | 13 +++++++++++++ 6 files changed, 30 insertions(+), 4 deletions(-) create mode 100644 utils/imageUrl.ts diff --git a/app/video/[bvid].tsx b/app/video/[bvid].tsx index 025de5d..c49e653 100644 --- a/app/video/[bvid].tsx +++ b/app/video/[bvid].tsx @@ -13,6 +13,7 @@ import { useVideoDetail } from '../../hooks/useVideoDetail'; import { useComments } from '../../hooks/useComments'; import { useVideoStore } from '../../store/videoStore'; import { formatCount } from '../../utils/format'; +import { proxyImageUrl } from '../../utils/imageUrl'; type Tab = 'intro' | 'comments'; @@ -90,7 +91,7 @@ export default function VideoDetailScreen() { - + {video.owner.name} + 关注 diff --git a/components/CommentItem.tsx b/components/CommentItem.tsx index 325a374..ceb1b88 100644 --- a/components/CommentItem.tsx +++ b/components/CommentItem.tsx @@ -3,13 +3,14 @@ import { View, Text, Image, StyleSheet } from 'react-native'; import { Ionicons } from '@expo/vector-icons'; import type { Comment } from '../services/types'; import { formatTime } from '../utils/format'; +import { proxyImageUrl } from '../utils/imageUrl'; interface Props { item: Comment; } export function CommentItem({ item }: Props) { return ( - + {item.member.uname} {item.content.message} diff --git a/components/MiniPlayer.tsx b/components/MiniPlayer.tsx index 38510d9..0e892d1 100644 --- a/components/MiniPlayer.tsx +++ b/components/MiniPlayer.tsx @@ -7,6 +7,7 @@ import { useRouter } from 'expo-router'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; import { Ionicons } from '@expo/vector-icons'; import { useVideoStore } from '../store/videoStore'; +import { proxyImageUrl } from '../utils/imageUrl'; export function MiniPlayer() { const { isActive, bvid, title, cover, clearVideo } = useVideoStore(); @@ -42,7 +43,7 @@ export function MiniPlayer() { onPress={() => router.push(`/video/${bvid}` as any)} activeOpacity={0.85} > - + {title} diff --git a/components/VideoCard.tsx b/components/VideoCard.tsx index bf506e7..caaa040 100644 --- a/components/VideoCard.tsx +++ b/components/VideoCard.tsx @@ -3,6 +3,7 @@ import { View, Text, Image, TouchableOpacity, StyleSheet, Dimensions } from 'rea import { Ionicons } from '@expo/vector-icons'; import type { VideoItem } from '../services/types'; import { formatCount, formatDuration } from '../utils/format'; +import { proxyImageUrl } from '../utils/imageUrl'; const { width } = Dimensions.get('window'); const CARD_WIDTH = (width - 24) / 2; @@ -17,7 +18,7 @@ export function VideoCard({ item, onPress }: Props) { diff --git a/dev-proxy.js b/dev-proxy.js index 47d1739..8296574 100644 --- a/dev-proxy.js +++ b/dev-proxy.js @@ -56,5 +56,14 @@ function makeProxy(targetHost) { app.use('/bilibili-api', makeProxy('api.bilibili.com')); app.use('/bilibili-passport', makeProxy('passport.bilibili.com')); +// Image CDN proxy — strips the host segment and forwards to the real CDN with Referer +app.use('/bilibili-img', (req, res) => { + const parts = req.url.split('/').filter(Boolean); + const host = parts[0]; + if (!host || !host.endsWith('.hdslb.com')) return res.status(403).end(); + req.url = '/' + parts.slice(1).join('/'); + makeProxy(host)(req, res); +}); + const PORT = process.env.PROXY_PORT || 3001; app.listen(PORT, () => console.log(`[Proxy] http://localhost:${PORT}`)); diff --git a/utils/imageUrl.ts b/utils/imageUrl.ts new file mode 100644 index 0000000..e2e3017 --- /dev/null +++ b/utils/imageUrl.ts @@ -0,0 +1,13 @@ +import { Platform } from 'react-native'; + +/** + * Web 端将 B站图片 CDN URL 转为本地代理地址,注入正确 Referer 绕过防盗链。 + * Native 端直接返回原 URL(App 请求头由 axios 拦截器统一设置)。 + */ +export function proxyImageUrl(url: string): string { + if (Platform.OS !== 'web' || !url) return url; + return url.replace( + /^https?:\/\/([a-z0-9]+\.hdslb\.com)/, + 'http://localhost:3001/bilibili-img/$1', + ); +}