在 Express JS 中,为什么 axios response.data 无需等待即可工作,但 fetch response.json() 需要等待?

问题描述 投票:0回答:1

我正在 Express.js 应用程序中实现 API 调用,并注意到 axios 和 fetch 之间的不同行为:

具体来说,在我的原始代码中的 Express 服务器代码中,当使用 fetch 时,没有

const data = response.json()
await
返回未定义的对象,并且无法正常工作。但是,使用 axios,即使不使用
const data = response.data;
await
也能正确检索数据对象。

(axios 与 fetch)

// axios
const response = await axios.get(url);
const data = response.data;  // works
// const data = await response.data;  // works

// fetch
// const response = await fetch(url);
// const data = response.json();  // doesn't work, return an undefined object
// const data = await response.json();  // works

我尝试实现这4种数据检索模式,并确认3种模式肯定有效,但作为技术知识,我想了解为什么不带await的fetch实现不起作用的根本原因。

[原始代码,用于重现行为] (服务器.js)

import express from 'express';
import bodyParser from 'body-parser';
import path from 'path';
import axios from 'axios';

const app = express();
const API_KEY = '3e11847ddf2fbb92d4f9bc989360f058';
const PORT = 3007;

app.use(express.static('public'));

app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());

const __dirname = path.resolve();

// Genre IDs for TMDB API
const genres = {
    'action': 28,
    'comedy': 35,
    'drama': 18,
    'horror': 27,
    'romance': 10749,
    'science fiction': 878
};

async function searchMovies(genre, year, rating) {
    try {
        const baseUrl = `https://api.themoviedb.org/3/discover/movie`;
        const queryParams = new URLSearchParams({
            api_key: API_KEY,
            with_genres: genres[genre],
            primary_release_year: year,
            'vote_average.gte': rating,
            sort_by: 'vote_average.desc',
            page: 1
        });
        const url = `${baseUrl}?${queryParams.toString()}`;

        console.log(url);

        // axios
        const response = await axios.get(url);
        // both work
        const data = response.data;  // works
        // const data = await response.data;  // works

        // fetch
        // const response = await fetch(url);
        // const data = response.json();  // doesn't work, return an undefined object
        // const data = await response.json();  // works


        if (data.total_results === 0) {
            throw new Error('No movies found matching your criteria');
        }

        return data.results.slice(0, 10); // Return top 10 results
    } catch (error) {
        throw new Error(error.response?.data?.message || error.message);
    }
}

app.get('/', (req, res) => {
    res.render(__dirname + '/movies.ejs', { 
        genres: Object.keys(genres),
        currentYear: new Date().getFullYear()
    });
});

app.post('/', async (req, res) => {
    try {
        const { genre, year, rating } = req.body;
        
        // Validation
        if (!genre || !year || !rating) {
            throw new Error('All fields are required');
        }

        if (year < 1900 || year > new Date().getFullYear()) {
            throw new Error('Invalid year');
        }

        if (rating < 0 || rating > 10) {
            throw new Error('Rating must be between 0 and 10');
        }

        const movies = await searchMovies(genre, year, rating);

        res.render(__dirname + '/movies.ejs', {
            genres: Object.keys(genres),
            currentYear: new Date().getFullYear(),
            movies: movies,
            searchParams: { genre, year, rating }
        });

    } catch (error) {
        res.render(__dirname + '/movies.ejs', {
            genres: Object.keys(genres),
            currentYear: new Date().getFullYear(),
            error: error.message,
            searchParams: req.body
        });
    }
});

app.listen(PORT, () => {
    console.log(`Server running on port ${PORT}`);
});


(电影.ejs)

<!DOCTYPE html>
<html>
<head>
    <title>Movie Search</title>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="main.css">
</head>
<body>
    <div class="container">
        <h1>Movie Search</h1>
        
        <form class="search-form" action="/" method="POST">
            <div class="form-group">
                <label for="genre">Genre:</label>
                <select name="genre" id="genre" required>
                    <option value="">Select a genre</option>
                    <% genres.forEach(genre => { %>
                        <option value="<%= genre %>" 
                            <%= locals.searchParams?.genre === genre ? 'selected' : '' %>>
                            <%= genre.charAt(0).toUpperCase() + genre.slice(1) %>
                        </option>
                    <% }) %>
                </select>
            </div>

            <div class="form-group">
                <label for="year">Release Year:</label>
                <input type="number" 
                       name="year" 
                       id="year" 
                       min="1900" 
                       max="<%= currentYear %>" 
                       value="<%= locals.searchParams?.year || currentYear %>" 
                       required>
            </div>

            <div class="form-group">
                <label for="rating">Minimum Rating (0-10):</label>
                <input type="number" 
                       name="rating" 
                       id="rating" 
                       min="0" 
                       max="10" 
                       step="0.1" 
                       value="<%= locals.searchParams?.rating || 7.0 %>" 
                       required>
            </div>

            <button type="submit">Search Movies</button>
        </form>

        <% if (locals.error) { %>
            <div class="error"><%= error %></div>
        <% } %>

        <% if (locals.movies) { %>
            <h2>Search Results</h2>
            <div class="movie-grid">
                <% movies.forEach(movie => { %>
                    <div class="movie-card">
                        <img class="movie-poster" 
                             src="https://image.tmdb.org/t/p/w500<%= movie.poster_path %>" 
                             alt="<%= movie.title %> poster">
                        <div class="movie-info">
                            <h3 class="movie-title"><%= movie.title %></h3>
                            <p><strong>Rating:</strong> <%= movie.vote_average %>/10 
                               (<%= movie.vote_count %> votes)</p>
                            <p><strong>Release Date:</strong> 
                               <%= new Date(movie.release_date).toLocaleDateString() %></p>
                            <p><%= movie.overview %></p>
                        </div>
                    </div>
                <% }) %>
            </div>
        <% } %>
    </div>
</body>
</html>

(仅供参考,/public/main.css)

.container {
    max-width: 1200px;
    margin: 0 auto;
    padding: 20px;
    font-family: Arial, sans-serif;
}
.search-form {
    background: #f5f5f5;
    padding: 20px;
    border-radius: 8px;
    margin-bottom: 30px;
}
.form-group {
    margin-bottom: 15px;
}
.form-group label {
    display: block;
    margin-bottom: 5px;
    font-weight: bold;
}
.form-group select,
.form-group input {
    width: 100%;
    padding: 8px;
    border-radius: 4px;
    border: 1px solid #ddd;
}
.movie-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
    gap: 20px;
}
.movie-card {
    border: 1px solid #ddd;
    border-radius: 8px;
    overflow: hidden;
    background: white;
    box-shadow: 0 2px 5px rgba(0,0,0,0.1);
}
.movie-poster {
    width: 100%;
    height: 400px;
    object-fit: cover;
}
.movie-info {
    padding: 15px;
}
.movie-title {
    font-size: 1.2em;
    margin: 0 0 10px 0;
}
.error {
    color: red;
    padding: 10px;
    background: #ffebee;
    border-radius: 4px;
    margin-bottom: 20px;
}
button {
    background: #4CAF50;
    color: white;
    padding: 10px 20px;
    border: none;
    border-radius: 4px;
    cursor: pointer;
}
button:hover {
    background: #45a049;
}

javascript express axios
1个回答
0
投票

AXIOS

axios.get()
返回 Promise 以及下一个响应模式 (docs):

{
  data: {},
  status: 200,
  statusText: 'ok',
  headers: {},
  config: {},
  request: {},
}

这就是为什么你只需等待

axios.get()
,它将返回 你准备好使用响应

获取

  • fetch()
    是一个Promise,包含服务器响应
  • json()
    是一个Promise,包含响应体内容

fetch 的工作方式不同,您必须进行更多操作才能使用所需的数据,但它更灵活,因为您可以直接访问服务器响应

© www.soinside.com 2019 - 2024. All rights reserved.