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

使用Axios与TheMovieDB API实现电影详情页的路由传参问题

解决电影详情页movieId传递失败导致的404问题

问题根源

  1. 后端Express接口未定义路由参数,无法接收前端传来的movieId
  2. 前端请求后端时,没有传递实际的movieId,而是用了:movieId占位符
  3. 后端请求TMDB API时,同样用了占位符而非实际参数值

第一步:修正后端server.js

修改接口路由,让它能捕获movieId参数,并正确传递给TMDB API:

const express = require('express');
const axios = require('axios');
const app = express();
const port = 5000;
const cors = require('cors');

app.use(cors({ origin: 'http://localhost:3000' }));

const API_KEY = '......';

// 电影列表接口保持不变
app.get('/api/movies', async (req, res) => {
    try {
        const response = await axios.get(
            `https://api.themoviedb.org/3/movie/popular?api_key=${API_KEY}`
        );
        res.json(response.data.results);
    } catch (error) {
        res.status(500).send('Error fetching data from API');
    }
});

// 修正电影详情接口:添加路由参数:movieId
app.get('/api/movieDetails/:movieId', async (req, res) => {
    try {
        // 从路由参数中获取movieId
        const { movieId } = req.params;
        const detailResponse = await axios.get(
            `https://api.themoviedb.org/3/movie/${movieId}?api_key=${API_KEY}`
        );
        res.status(200).json(detailResponse.data);
    } catch (error) {
        // 区分TMDB请求失败或其他错误
        res.status(error.response?.status || 500).send('Error fetching movie details');
    }
});

app.listen(port, () => {
    console.log(`Backend is running on http://localhost:${port}`);
});

第二步:修正前端MovieDetailComponent.js

用React Router的useParams获取路由参数,正确请求后端接口,并优化状态处理:

import React, { useState, useEffect } from 'react';
import axios from 'axios';
import { useParams } from 'react-router-dom'; // 引入useParams

const posterUrl = 'https://media.themoviedb.org/t/p/w220_and_h330_face';
const posterDetailUrl = 'https://media.themoviedb.org/t/p/w300_and_h450_bestv2';
const backdropBaseUrl = 'https://media.themoviedb.org/t/p/w1920_and_h800_multi_faces'; // 只存基础路径,后续拼接图片地址

const MovieDetail = () => {
    const { movieId } = useParams(); // 从路由获取movieId
    const [movie, setMovie] = useState(null); // 直接存储电影对象,无需转数组
    const [isLoading, setIsLoading] = useState(true);
    const [error, setError] = useState(null);

    const fetchData = async () => {
        setIsLoading(true);
        try {
            // 请求后端接口,传递实际的movieId
            const response = await axios.get(`http://localhost:5000/api/movieDetails/${movieId}`);
            setMovie(response.data);
            setError(null);
        } catch (err) {
            setError(err.message);
            setMovie(null);
        } finally {
            setIsLoading(false);
        }
    };

    useEffect(() => {
        if (movieId) { // 确保movieId存在再发起请求
            fetchData();
        }
    }, [movieId]); // movieId变化时重新请求数据

    if (isLoading) return <div>加载中...</div>;
    if (error) return <div>错误:{error}</div>;
    if (!movie) return <div>未找到电影数据</div>;

    return (
        <div className="App" style={{ 
            backgroundImage: `url(${backdropBaseUrl + movie.backdrop_path})`, 
            backgroundSize: 'cover',
            padding: '15px' 
        }}>
            <div style={{ margin: '15px', padding: '15px', backgroundColor: 'rgba(255,255,255,0.7)' }}>
                <h1>Watch This</h1>
                <h2>{movie.title || movie.original_title}</h2>
                <div>
                    <img 
                        src={`${posterUrl + movie.poster_path}`} 
                        alt={movie.title}
                        style={{ maxWidth: '220px' }}
                    />
                    <p>
                        <strong>&#9733; {movie.vote_average.toFixed(1)}</strong>
                        ({movie.vote_count}) | {movie.runtime} minutes
                    </p>
                </div>
                <div>
                    <h4>Overview</h4>
                    <p>{movie.overview}</p>
                    <h4>Genres</h4>
                    <p>{movie.genres.map(g => g.name).join(', ')}</p>
                </div>
            </div>
        </div>
    );
};

export default MovieDetail;

关键优化点说明

  1. 后端路由参数:通过:movieId定义路由参数,Express自动将URL对应值存入req.params.movieId
  2. 前端路由参数:用useParams替代手动切割路径,更可靠且符合React Router最佳实践
  3. 状态处理:直接存储电影对象而非数组,取值更直观(如movie.title比data[10]可读性更高)
  4. 用户体验:添加加载、错误、空数据的UI反馈,避免页面空白或混乱

内容的提问来源于stack exchange,提问作者Wes Hightower

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.02 04:34:52