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

Posted

技术标签:

【中文标题】Fetch() 没有从服务器返回数据作为响应【英文标题】:Fetch() is not returning data from server in response 【发布时间】:2017-06-05 00:02:31 【问题描述】:

我的 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 问题 【参考方案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 发出重新渲染时显示新播放器。

【讨论】:

以上是关于Fetch() 没有从服务器返回数据作为响应的主要内容,如果未能解决你的问题,请参考以下文章

Fetch:使用获取响应设置变量并从函数返回

使用 fetch API 从数组中获取数据的问题 [重复]

如何从fetch获取响应值而不是没有值的promise?

我如何使用 fetch API 并在状态下存储响应?

从 Fetch 中捕获 200 OK 以外的响应

Fetch Api:无法从本地主机获取数据