You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过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;

关键修改说明

  1. baseQuery重构:

    • 将baseUrl设为allorigins.win地址,每个endpoint通过params传递编码后的完整iTunes URL,避免路径拼接错误。
    • 添加transformResponse,自动解析代理返回的contents字段为JSON,直接拿到iTunes原始响应。
  2. getPodcastEpisodes修正:

    • 指定返回类型为LookupResponse,符合TypeScript类型校验要求。
    • 构建完整的iTunes lookup请求URL,编码后通过代理转发。
  3. getEpisodeById调整:

    • 由于iTunes无单剧集直接查询接口,改用queryFn先获取目标播客的全量剧集,再筛选出对应ID的剧集。

组件使用示例

在播客详情组件中调用接口:

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 23:49:57