【问题标题】:Unexpected end of JSON input when using Promise.all() and put method in fetch使用 Promise.all() 并将方法放入 fetch 时 JSON 输入意外结束
【发布时间】:2021-10-08 11:28:54
【问题描述】:

当我尝试从 API 获取邮件内容并同时更新其读取状态时,我在使用 Javascript 时遇到了问题。控制台中的错误信息是:

SyntaxError: Unexpected end of JSON input
    at inbox.js:98

日志中的错误承诺如下。

1: Promise
[[Prototype]]: Promise
[[PromiseState]]: "rejected"
[[PromiseResult]]: SyntaxError: Unexpected end of JSON input at http://127.0.0.1:8000/static/mail/inbox.js:98:30
message: "Unexpected end of JSON input"
stack: "SyntaxError: Unexpected end of JSON input\n    at http://127.0.0.1:8000/static/mail/inbox.js:98:30"

第 98 行的代码是:

let res2 = response[1].json();

完整的js代码如下。我检查了名为res1res2 的承诺。似乎问题在于res2,因为它的返回是rejected。我尝试了不同的方法来解决它,但失败了。我也不明白为什么catch 函数没有捕捉到它。提前谢谢你。

虽然它每次都返回SyntaxErrorfetch 的两个函数都已经工作了……

async function show_single_mail(email_id){
 
  // Show content of selected email

  document.querySelector('#mails_table').style.display = 'none';

  const email_div = document.createElement('div');
  document.querySelector('#emails-view').append(email_div);

  // Obtain email content and update its read status concurrently

  const option2 = {
    method: 'PUT', 
    body: JSON.stringify({read: true})}

  Promise.all([fetch(`/emails/${email_id}`), fetch(`/emails/${email_id}`, option2)])
    .then(response => {
      let res1 = response[0].json();
      let res2 = response[1].json();
      console.log([res1, res2]);
      return Promise.all([res1, res2])
    })
    .then(results => {
      result = results[0];
      email_div.innerHTML = 
      `<h3>Subject: ${result.subject}</h3><br>` +
      `<p>Sender: ${result.sender}</p><br>`+
      `<p>Receiver: ${result.recipients}</p><br>`+
      `<p>Time: ${result.timestamp}</p><br>`+
      `<p>Content: ${result.body}</p>`;
    })
    .catch(err => console.log(err))
}

【问题讨论】:

  • response[1]的内容是什么?看起来它不是(有效的)JSON
  • .json() 也是一个承诺...最简单的方法是将您的第一个 .then 块回调转换为 async 然后在 .json() 调用上使用 await
  • fetch 不会拒绝不成功的状态码(即状态码 4xx),因此您必须自己检查结果。在访问响应正文之前,请先检查 response[0].status == 2xxresponse[1].status == 2xx 是否。当状态为 4xx 时,似乎服务器没有发送 JSON 对象。因此,当您在失败的请求上调用 res.json() 时,它会引发错误,因为主体不是有效的 jsn
  • 您还可以将.json() 更改为.text() 并将results 的值记录在下一个.then() 中,这样您就可以看到从服务器实际返回的内容。 (或使用浏览器的开发者工具网络选项卡查看响应。)
  • 我尝试在.json() 上添加asyncawait。它也不起作用。问题仍然存在。我已经有Promise.all() 了。它已经满足异步要求了吗?

标签: javascript json promise fetch


【解决方案1】:

您正在执行两个并行请求

Promise.all([fetch(...), fetch(...)])

这很好。但是当您处理结果时,您并没有检查请求是否成功,并且fetch 不会拒绝 4xx 状态代码。此外,您的服务器显然不会为不成功的请求返回 JSON,而只会返回文本。甚至可能是第二个请求成功,但没有有效的 json 正文。没有人知道你的 API 到底做了什么。

当你现在这样做

.then(responses => {
   responses[0].json();  //this response has a valid json body
   responses[1].json();  //this one doesn't
})

response[1] 的主体不能被解析为 json(responses[1].json() 试图这样做)。因此,会引发错误。因此,您必须先检查您的请求是否成功/返回 json,然后才能读取它们的正文

.then(responses => {
   let s = responses.filter(x => x.ok);  //status == 2xx
   let f = responses.filter(x => !x.ok); //status != 2xx  
   //do something with failed requests and
   //only read the body for successful responses
   //return Promise.all(s.map(x => x.json()); 

   //or try to read json for successful and text for unsuccessful responsees
   //return Promise.all(responses.map(r => r.ok ? r.json() : r.text()));

   //or try to check the contenttype of the responses (if the server correctly sets them
   //return Promise.all(responses.map(r => r.headers.get("content-type").includes("application/json") 
   //    ? res.json()
   //    : res.text()
   //  ));
})
.then(responses => {
  //display them
});

【讨论】:

  • 感谢您的回答。这很有帮助。我检查了我的代码并用下面的代码解决了这个问题。我认为问题可能是由fetch.POSTfetch.PUT 的不同返回引起的。 fetch.PUT 的返回似乎无法与fetch.POST 合并。 Promise.all([fetch(`/emails/${email_id}`), fetch(`/emails/${email_id}`, option2)]).then(responses =&gt; {return responses[0].json()}).then(result =&gt; {console.log(result);
猜你喜欢
  • 2018-10-03
  • 2018-01-23
  • 1970-01-01
  • 1970-01-01
  • 2020-07-10
  • 2016-10-26
  • 2015-08-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多