【问题标题】:Fetch() is not returning data from server in responseFetch() 没有从服务器返回数据作为响应
【发布时间】:2025-12-07 13:45:02
【问题描述】:

我的 fetch 从服务器返回任何数据时遇到问题,我似乎不太明白为什么。

我认为在服务器发回任何 JSON 之前,promise 可能已经解决了,所以我最近更新了我的模型以使用 promises。我对 promises 和 fetch API 不熟悉,所以请多多包涵。

我也愿意恢复回调并将我的 Player.findPlayer.create 方法放回 Players.js 路由并完全避免服务器端的承诺。

玩家模型(添加承诺后)

// require mongoose for data modeling
import mongoose from 'mongoose';
import Q from 'q';

const Schema = mongoose.Schema;

// define player schema
const PLAYER_SCHEMA = new Schema({
  name: String,
  score: Number
});

PLAYER_SCHEMA.statics.createPlayer = (name, score) => {
  const deferred = Q.defer();

  Player.create({
    name,
    score,
  }, (error, player) => {
    if (error) {
      deferred.reject(new Error(error));
    }

    deferred.resolve(player);
  });

  return deferred.promise;
}

PLAYER_SCHEMA.statics.getPlayers = () => {
  const deferred = Q.defer();

  Player.find({})
    .sort({
      score: 'desc'
    })
    .limit(5)
    .exec((error, players) => {
        if (error) {
          deferred.reject(new Error(error));
        }

        deferred.resolve(players);
  });

  return deferred.promise;
}

let Player = mongoose.model('Player', PLAYER_SCHEMA);

// first param is the singular name for the collection,
// mongoose automatically looks for the plural version
// so our db will have a 'players' collection
export default Player;

路线(添加承诺后)

// dependencies
import express from 'express';
import Player from '../models/player';

const ROUTER = express.Router();

ROUTER.post('/', (req, res) => {
  const name = req.body.name;
  const score = req.body.score;
  const promise = Player.createPlayer(name, score);

  promise.then((response) => {
    res.status(201).json(response);
  }).catch((err) => {
    res.send(err)
  });

});

ROUTER.get('/', (req, res) => {
  const promise = Player.getPlayers();

  promise.then((response) => {
    console.log(response);
    res.status(200).json(response);
  }).catch((err) => {
    res.send(err)
  });
});

export default ROUTER;

在 Postman 中测试这些端点可以正常工作,所以我认为问题不在于服务器。

这是我怀疑我有问题的地方。

Client.js(存储 AJAX 方法的地方)

function createPlayer(playerData, onError, cb) {
  return fetch('/api/players', {
    method: 'post',
    body: JSON.stringify(playerData),
    headers: {
      'Accept': 'application/json',
      'Content-Type': 'application/json',
    },
  }).then(checkStatus)
    .then(cb)
    .catch(onError);
}

function getPlayers(success, onError) {
  return fetch('/api/players', {
    headers: {
      'Accept': 'application/json',
      'Content-Type': 'application/json',
    },
  }).then(checkStatus)
    .then(parseJSON)
    .then(success)
    .catch(onError);
}

function checkStatus(response) {
  if (response.status >= 200 && response.status < 300) {
    return response;
  } else {
    const error = new Error(`HTTP Error ${response.statusText}`);
    error.status = response.statusText;
    error.response = response;
    throw error;
  }
}

function parseJSON(response) {
  return response.json();
}

const Client = {
  createPlayer,
  getPlayers
};
export default Client;

App.jsx(省略了很多代码)

//所有其​​他代码省略

  const playerData = {
    name,
    score: this.state.totalScore,
  };

  client.createPlayer(playerData,
    (err) => {
      // TODO: improve error message
      console.log(err);
    },
    client.getPlayers((data) => {
      // array of objects containing all but most recent entry
      console.log(data); 
      this.setState({
        inputScreen: false, // hide the input screen
        highScoreScreen: true, // show the high score screen
        yeti: yetiWin,
        highScores: [...this.state.highScores, ...data],
      });
    }, (err) => {
      // TODO: improve this error message
      console.log(err);
    })
  );   

//所有其​​他代码省略

数据变量从不包含新创建的玩家,但它确实包含其他玩家。因此创建和读取操作在服务器端进行。当我将App.jsx 修改为如下内容时:

App.jsx(试用版)

  const playerData = {
    name,
    score: this.state.totalScore,
  };

  client.createPlayer(playerData,
    (err) => {
      // TODO: improve error message
      console.log(err);
    },
    (res) => {
      // should contain something like:
      // {
      //     "__v": 0,
      //     "_id": "5881922f441fda40ccc52f83",
      //     "name": "player name",
      //     "score": "123"
      // }
      // right?
      console.log(res.json());
      console.log(res);
      console.log(res.body);
    }
  );   

当我登录 res.json resres.body 时,我得到:

承诺{[[PromiseStatus]]:“待定”,[[PromiseValue]]:未定义}

响应{type: "basic", url: "http://localhost:3000/api/players", status: 200, ok: true, statusText: "OK"…}

可读流{}

当我在邮递员中测试我的 POST 端点 (http://localhost:3001/api/players) 时,服务器会使用包含我想要的数据的 JSON 对象进行响应。无论出于何种原因,client.createPlayer 都不会从服务器返回数据。当然,这只是问题的一部分。

理论上,一旦我的client.createPlayer 解析并调用client.getPlayers 作为client.createPlayer 的回调,该方法应该返回我想要的数据,包括新创建的播放器,对吧?

但似乎并非如此。

我做错了什么?

【问题讨论】:

  • 这个http://localhost:3001 看起来很可疑......我认为http://localhost:3001 也是发出请求的页面的加载位置,而不是来自像http://localhost:80 这样的不同主机或其他东西 - 我可以在 fetch 中看到您的 URL 是 '/api/players' 所以,这是实际代码,您没有删除任何内容只是为了问题,这不是“跨源”请求,是吗?
  • @JaromandaX 我正在使用 create-react-app,因此客户端服务器在 localhost:3000 上运行,而 express 服务器在 localhost:3001 上运行。客户端设置为代理对 localhost:3001 的请求。
  • 好的 - 只是确保这不是 CORS 问题

标签: reactjs express mongoose promise fetch


【解决方案1】:

有趣的是,通过将App.jsx 中的代码更改为以下代码,我能够产生我想要的结果。但是,我不会将我的答案标记为正确的解决方案,因为我不完全理解为什么此更改会起作用。

如果有人想插话并解释为什么现在这样有效,我很想听听原因。

App.jsx(固定)

// all other code omitted 

  client.createPlayer(playerData, (err) => {
    console.error(err);
  }, (data) => {
    this.setState({
      highScores: [...this.state.highScores, ...data],
    });
  });      

  client.getPlayers((data) => {
    this.setState({
      inputScreen: false, // hide the input screen
      highScoreScreen: true, // show the high score screen
      yeti: yetiWin,
      highScores: [...this.state.highScores, ...data],
    });
  }, (err) => {
    console.error(err);
  });

// all other code omitted

您会注意到我不再调用client.getPlayers 作为对client.createPlayer 的成功回调。最重要的是,我使用来自client.createPlayer 的返回数据并将其添加到状态中作为备用,以防client.createPlayer 方法在client.getPlayers 方法之前没有完成。这将确保在setState 发出重新渲染时显示新播放器。

【讨论】: