fetch 给出一个空的响应体

Posted

技术标签:

【中文标题】fetch 给出一个空的响应体【英文标题】:fetch gives an empty response body 【发布时间】:2016-08-18 20:00:27 【问题描述】:

我有一个 react/redux 应用程序,我正在尝试向服务器发出一个简单的 GET 请求:

fetch('http://example.com/api/node', 
  mode: "no-cors",
  method: "GET",
  headers: 
    "Accept": "application/json"
  
).then((response) => 
  console.log(response.body); // null
  return dispatch(
    type: "GET_CALL",
    response: response
  );
)
.catch(error =>  console.log('request failed', error); );

问题是.then() 函数中的响应正文是空的,我不知道为什么。我在网上检查了示例,看起来我的代码应该可以工作,所以我显然在这里遗漏了一些东西。 问题是,如果我在 Chrome 的开发工具中检查网络选项卡,就会发出请求并收到我正在寻找的数据。

有人能介绍一下这个吗?

编辑:

我尝试转换响应。

使用.text():

fetch('http://example.com/api/node', 
  mode: "no-cors",
  method: "GET",
  headers: 
    "Accept": "application/json"
  
)
.then(response => response.text())
.then((response) => 
  console.log(response); // returns empty string
  return dispatch(
    type: "GET_CALL",
    response: response
  );
)
.catch(error =>  console.log('request failed', error); );

.json():

fetch('http://example.com/api/node', 
  mode: "no-cors",
  method: "GET",
  headers: 
    "Accept": "application/json"
  
)
.then(response => response.json())
.then((response) => 
  console.log(response.body);
  return dispatch(
    type: "GET_CALL",
    response: response.body
  );
)
.catch(error =>  console.log('request failed', error); ); // Syntax error: unexpected end of input

查看 chrome 开发工具:

【问题讨论】:

【参考方案1】:

我刚碰到这个。正如answer 中提到的,使用mode: "no-cors" 会给你一个opaque response,它似乎不会在正文中返回数据。

不透明:对跨域资源的“no-cors”请求的响应。 Severely restricted.

就我而言,我使用的是Express。在我安装cors for Express 并配置它并删除mode: "no-cors" 后,我得到了一个承诺。响应数据将在 Promise 中,例如

fetch('http://example.com/api/node', 
  // mode: 'no-cors',
  method: 'GET',
  headers: 
    Accept: 'application/json',
  ,
,
).then(response => 
  if (response.ok) 
    response.json().then(json => 
      console.log(json);
    );
  
);

【讨论】:

对我来说,所需要的只是将.then(json => 添加到我的response.json() 语句的末尾。谢谢! @MikeKellogg 只是提醒一下,如果您想保持代码整洁,您可以 return response.json() 并将 .then(json=> 部分放在最后一个括号和分号之间。 ).then(json=>); 如果您离开域并使用相对URI,它似乎可以与no-cors一起使用 我使用的是 AWS API Gateway,在我的 lambda 中,我在响应中缺少此标头 "Access-Control-Allow-Origin": "*"。添加并删除 no-cors 对我有用。 对于那些希望打开no-cors 模式以试图绕过某些 CORS 限制的人,不幸的是,无法解析从这些类型的请求返回的不透明响应。我非常困惑,因为我可以在浏览器开发人员工具中清楚地看到正确的响应,但它从来没有通过我的代码。有关该主题的更多讨论可以在这里找到:***.com/a/54906434/3513260【参考方案2】:

您需要将response 转换为json,然后才能访问response.body

来自docs

fetch(url)
  .then(response => response.json())
  .then(json => 
    console.log('parsed json', json) // access json.body here
  )

【讨论】:

很好的答案,感谢您对文档的参考。文档还显示了如果您使用 JSON 以外的其他内容(例如文本)该怎么做 - 它可以显示相同的行为并且解决方案非常相似(使用 text() 而不是 json() )。【参考方案3】:

这需要更改前端 JS 和后端发送的标头。

前端

删除提取选项中的"mode":"no-cors"

fetch(
  "http://example.com/api/docs", 
  
    // mode: "no-cors",
    method: "GET"
  
)
  .then(response => response.text())
  .then(data => console.log(data))

后端

当您的服务器响应请求时,请包含指定请求来源的 CORS 标头。如果您不关心来源,请指定* 通配符。

原始响应应包含这样的标头。

Access-Control-Allow-Origin: *

【讨论】:

【参考方案4】:

您必须阅读响应的正文:

fetch(url)
  .then(res => res.text()) // Read the body as a string

fetch(url)
  .then(res => res.json()) // Read the body as JSON payload

一旦您阅读了正文,您就可以对其进行操作:

fetch('http://example.com/api/node', 
  mode: "no-cors",
  method: "GET",
  headers: 
    "Accept": "application/json"
  
)
  .then(response => response.json())
  .then(response => 
    return dispatch(
      type: "GET_CALL",
      response: response
    );
  )

【讨论】:

感谢您的回答!我试过了,但我仍然可以得到正确的响应。检查已编辑的问题。 @RazvanIlin 使用.json() 而不是.text() 对不起,我刚刚意识到我在上一个示例中复制了错误的 sn-p。我实际上在那里使用json(),但我得到了语法错误,我认为它会被触发,因为它无法将响应转换为 json 试过这个,它对我有用。 response.json() 创造了奇迹。一旦我有了它,我就可以 console.log 并得到我的回复。谢谢 我仍然试图围绕这个no-cors 模式。我也有类似的情况。在这里使用解决方案的变体,no-cors fetch 似乎成功了……没有 x-origin 错误,在我的网络检查器中,我可以在预览和响应中看到数据。但我似乎无法访问传递给我的then 的响应对象中的数据。 json() text() 似乎都没有做太多。不透明的响应是否意味着它获取数据然后nulls 它所以完成后无法访问? :-/【参考方案5】:
fetch("http://localhost:8988/api", 
        //mode: "no-cors",
        method: "GET",
        headers: 
            "Accept": "application/json"
        
    )
    .then(response => 
        return response.json();
    )
    .then(data => 
        return data;
    )
    .catch(error => 
        return error;
    );

这对我有用。

【讨论】:

【参考方案6】:
fetch("http://localhost:8988/api", 
    method: "GET",
    headers: 
       "Content-Type": "application/json"
    
)
.then((response) =>response.json());
.then((data) => 
    console.log(data);
)
.catch(error => 
    return error;
);

【讨论】:

虽然此代码可能会回答 OP 的问题,但几句话的解释将有助于当前和未来的读者理解您的回复。 这实际上与此处的其他答案非常相似。不确定 SO 的政策,但我不确定是否允许这样做 只是不一样。 “内容类型”是唯一的。可惜它对我不起作用:(【参考方案7】:

尝试使用response.json():

fetch('http://example.com/api/node', 
  mode: "no-cors",
  method: "GET",
  headers: 
    "Accept": "application/json"
  
).then((response) => 
  console.log(response.json()); // null
  return dispatch(
    type: "GET_CALL",
    response: response.json()
  );
)
.catch(error =>  console.log('request failed', error); );

【讨论】:

【参考方案8】:

在许多情况下,您需要在 express 节点应用程序中添加 bodyParser 模块。 然后在 app.use(express.static('www')); 下方的 app.use 部分中 添加这两行 app.use(bodyParser.urlencoded( extended: true )); app.use(bodyParser.json());

【讨论】:

以上是关于fetch 给出一个空的响应体的主要内容,如果未能解决你的问题,请参考以下文章

DEBUG关于SpringMVC的返回响应体文本json两种数据的乱码问题

Django请求生命周期之响应内容

UnityWebRequest.downloadHandler.text为空,尽管POST方法返回响应

Fetch - 响应预检响应

axios在20秒内给出响应,但具有相同请求有效载荷的相同api在6秒内从邮递员那里得到响应

Java中的HttpServletResponse响应