如何通过iTunes API获取播客剧集列表?React项目问题
解决React + RTK Query获取iTunes播客剧集的问题
核心问题分析
- 当前
baseQuery设置错误:把ITUNES_URL直接编码后拼在代理地址里,导致后续endpoint的URL错误拼接,最终请求地址无效。 allorigins.win返回的响应包含contents字段,里面才是iTunes的原始JSON数据,未做响应转换处理。- iTunes的
lookup接口实际返回JSON格式,浏览器显示为txt只是响应头的表现问题,可直接解析。
修正后的代码实现
首先添加TypeScript类型定义(适配项目栈要求):
// 播客剧集的核心字段类型,可根据实际返回补充 export interface PodcastEpisode { trackId: number; trackName: string; description: string; releaseDate: string; trackTimeMillis: number; episodeUrl: string; } // iTunes lookup接口的统一响应结构 export interface LookupResponse { resultCount: number; results: PodcastEpisode[]; }
修改podcastApi的实现:
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'; const ITUNES_BASE_URL = 'https://itunes.apple.com'; export const podcastApi = createApi({ reducerPath: 'podcastApi', // 重构baseQuery:用allorigins代理请求,同时处理响应转换 baseQuery: fetchBaseQuery({ baseUrl: 'https://api.allorigins.win/get', transformResponse: (response: { contents: string }) => JSON.parse(response.contents), }), endpoints: (builder) => ({ getPodcasts: builder.query({ query: () => ({ params: { url: encodeURIComponent(`${ITUNES_BASE_URL}/us/rss/toppodcasts/limit=100/genre=1310/json`), }, }), }), getPodcastById: builder.query({ query: (id) => ({ params: { url: encodeURIComponent(`${ITUNES_BASE_URL}/lookup?id=${id}`), }, }), }), // 修正获取剧集的endpoint getPodcastEpisodes: builder.query<LookupResponse, string>({ query: (podcastId) => ({ params: { url: encodeURIComponent(`${ITUNES_BASE_URL}/lookup?id=${podcastId}&country=US&media=podcast&entity=podcastEpisode&limit=100`), }, }), }), // 调整单剧集获取逻辑:iTunes无直接接口,先拿全量再筛选 getEpisodeById: builder.query<PodcastEpisode | undefined, { podcastId: string; episodeId: string }>({ queryFn: async ({ podcastId, episodeId }, _queryApi, _extraOptions, fetchWithBQ) => { const response = await fetchWithBQ({ params: { url: encodeURIComponent(`${ITUNES_BASE_URL}/lookup?id=${podcastId}&country=US&media=podcast&entity=podcastEpisode&limit=100`), }, }); if ('error' in response) { return { error: response.error }; } const data = response.data as LookupResponse; const targetEpisode = data.results.find(ep => ep.trackId.toString() === episodeId); return { data: targetEpisode }; }, }), }), }); // 导出RTK Query自动生成的钩子 export const { useGetPodcastsQuery, useGetPodcastByIdQuery, useGetPodcastEpisodesQuery, useGetEpisodeByIdQuery, } = podcastApi;
关键修改说明
baseQuery重构:
- 将
baseUrl设为allorigins.win地址,每个endpoint通过params传递编码后的完整iTunes URL,避免路径拼接错误。 - 添加
transformResponse,自动解析代理返回的contents字段为JSON,直接拿到iTunes原始响应。
- 将
getPodcastEpisodes修正:
- 指定返回类型为
LookupResponse,符合TypeScript类型校验要求。 - 构建完整的iTunes lookup请求URL,编码后通过代理转发。
- 指定返回类型为
getEpisodeById调整:
- 由于iTunes无单剧集直接查询接口,改用
queryFn先获取目标播客的全量剧集,再筛选出对应ID的剧集。
- 由于iTunes无单剧集直接查询接口,改用
组件使用示例
在播客详情组件中调用接口:
import { useGetPodcastEpisodesQuery } from './path/to/podcastApi'; function PodcastDetails({ podcastId }: { podcastId: string }) { const { data, error, isLoading } = useGetPodcastEpisodesQuery(podcastId); if (isLoading) return <div>加载中...</div>; if (error) return <div>加载失败:{(error as Error).message}</div>; return ( <div> <h2>剧集列表</h2> <ul> {data?.results.map(episode => ( <li key={episode.trackId}> <h3>{episode.trackName}</h3> <p>发布时间:{new Date(episode.releaseDate).toLocaleDateString()}</p> <audio controls src={episode.episodeUrl} /> </li> ))} </ul> </div> ); }
内容的提问来源于stack exchange,提问作者Alfonso De La Guardia
相关产品推荐
相关产品推荐

