Fetch()不会从服务器返回数据作为响应

时间:2017-01-20 04:34:52

标签: reactjs express mongoose promise fetch

我的fetch存在问题,从服务器返回任何数据,我似乎无法理解原因。

我想也许这个承诺在服务器发回任何JSON之前就解决了,所以我最近更新了我的模型以利用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]]:&#34;待定&#34;,[[PromiseValue]]:undefined}

     

回复{type:&#34; basic&#34;,url:&#34; http://localhost:3000/api/players&#34;,status:200,ok:true,statusText:&#34; OK&#34; ...}

     

ReadableStream {}

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

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

然而,情况似乎并非如此。

我做错了什么?

1 个答案:

答案 0 :(得分: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发出重新渲染后显示新玩家。