Fetch() 没有从服务器返回数据作为响应

Fetch() is not returning data from server in response

我在从服务器获取 return 任何数据时遇到问题,我似乎不太明白为什么。

我想也许在服务器发回任何 JSON 之前 promise 就解决了,所以我最近更新了我的模型以也利用 promises。我是 promises 和 fetch API 的新手,所以请多多包涵。

I am willing to revert back too callbacks and put my Player.find and Player.create methods back in the Players.js route and avoid promises on the server side altogether.

玩家模型(添加promise后)

// 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;

路由(添加promise后)

// 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 我得到:

Promise {[[PromiseStatus]]: "pending", [[PromiseValue]]: undefined}

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

ReadableStream {}

当我在 postman 中测试我的 POST 端点 (http://localhost:3001/api/players) 时,服务器响应一个包含我想要的数据的 JSON 对象。无论出于何种原因 client.createPlayer 都没有 return 来自服务器的数据。当然,这只是问题的一部分。

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

然而情况似乎并非如此。

我做错了什么?

有趣的是,通过将 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 发出 re-render.

就会显示新玩家