Promise中未捕获的SyntaxError: JSON输入意外终止

20
我试图向我的服务器发送一个新的推送订阅,但遇到了一个错误“Uncaught (in promise) SyntaxError: Unexpected end of JSON input”,控制台显示在我的索引页第1行,显然不是这种情况。 我怀疑出现问题的函数(因为当我将其注释掉时不会抛出错误)是sendSubscriptionToBackEnd(subscription),它在以下位置被调用:
function updateSubscriptionOnServer(subscription) {
  const subscriptionJson = document.querySelector('.js-subscription-json');
  const subscriptionDetails = document.querySelector('.js-subscription-details');

  if (subscription) {
    subscriptionJson.textContent = JSON.stringify(subscription);
    sendSubscriptionToBackEnd(subscription);
    subscriptionDetails.classList.remove('is-invisible');
  } else {
    subscriptionDetails.classList.add('is-invisible');
  }
}

该函数本身(在上述函数之前):

 function sendSubscriptionToBackEnd(subscription) {
  return fetch('/path/to/app/savesub.php', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json'
    },
    body: JSON.stringify(subscription)
  })
  .then(function(response) {
    if (!response.ok) {
      throw new Error('Bad status code from server.');
    }

    return response.json();
  })
  .then(function(responseData) {
    if (!(responseData.data && responseData.data.success)) {
      throw new Error('Bad response from server.');
    }
  });
}

我已经尝试将fetch调用中的单引号替换为双引号,但结果相同。

我知道JSON应该被填充,因为它在updateSubscriptionOnServer()函数中打印到屏幕上,使用subscriptionJson.textContent = JSON.stringify(subscription); ,并且我在google codelab的示例服务器中使用了该输出以成功接收推送。

编辑:这是JSON作为字符串,但我没有看到语法错误:

{"endpoint":"https://fcm.googleapis.com/fcm/send/dLmthm1wZuc:APA91bGULRezL7SzZKywF2wiS50hXNaLqjJxJ869y8wiWLA3Y_1pHqTI458VIhJZkyOsRMO2xBS77erpmKUp-Tg0sMkYHkuUJCI8wEid1jMESeO2ExjNhNC9OS1DQT2j05BaRgckFbCN","keys":{"p256dh":"BBz2c7S5uiKR-SE2fYJrjPaxuAiFiLogxsJbl8S1A_fQrOEH4_LQjp8qocIxOFEicpcf4PHZksAtA8zKJG9pMzs=","auth":"VOHh5P-1ZTupRXTMs4VhlQ=="}}

有什么想法吗??


你能提供服务器的响应吗? - Douwe de Haan
1
也许问题在于您使用了 JSON.stringify() 而不是 JSON.parse() - alex kucksdorf
你的JSON长什么样?看起来好像有语法错误。 - jeremiah.trein
我同意Alex的观点。你忘记了你使用了“POST”。 - jeremiah.trein
我不知道你的JSON以哪种格式出现,但也许只需将你的“subscription”作为POST请求的主体即可。 - alex kucksdorf
显示剩余6条评论
6个回答

20
这可能是端点没有在响应头中传递适当的参数所导致的问题。
在Chrome的控制台中,进入“网络”标签,检查端点发送的标题,应该包含这个: 允许来自本地主机和跨域请求的正确响应示例 请要求API开发人员在标题中包含此内容。
"Access-Control-Allow-Origin" : "*", 
"Access-Control-Allow-Credentials" : true 

我将服务器端点更改为返回HTTP 200而不是HTTP 2004状态代码,并以此方式解决了它。 - Matthias Adriaens

7
这种情况也发生在我运行Express.js服务器并使用Brave浏览器时。在我的情况下,这是一个CORS问题。我按照以下步骤解决了我的问题: (由于这是一个Express框架,我正在使用app.get)
- 服务器端:
 res.set({
        "Content-Type": "application/json",
        "Access-Control-Allow-Origin": "*",
    });

在客户端,我使用 Fetch 获取数据但禁用了 CORS 选项。

// mode: "no-cors" //disabled this in Fetch

这解决了我在使用Express获取数据时遇到的问题。


4
这可能是因为你没有从服务器发送任何JSON 或者 这可能是因为你正在发送无效的JSON。
你的代码可能看起来像这样: res.end();

2

其中一个陷阱是返回的数据不是JSON格式,而只是普通文本负载,无论设置了什么标头。例如,通过Express发送:

res.send({a: "b"});

相比于
res.json({a: "b"});

会返回这个令人困惑的错误。在网络活动中不容易检测到,因为它看起来相当合法。


1

对于后来查看此处的人。我收到了这个错误,不是因为我的头文件,而是因为我没有将响应体递归地附加到字符串中以供稍后JSON.parse。

根据 MDN示例(我已经删除了一些与他们的示例不相关的部分):

reader.read().then(function processText({ done, value }) {
    if (done) {
      console.log("Stream complete");
      return;
    }
    result += chunk;
    return reader.read().then(processText);
  });

对于我的问题,我必须在.then内使用一个命名函数(而不是匿名的() => {}), 递归地将结果连接在一起。 一旦完成为true,对总连接结果执行其他操作。 以防万一您将来有用,并且您的问题与初始JSON流响应中的完成值不为true有关。

-1

我知道这个问题已经有答案了,但我想加上我的想法。

当你的响应主体为空且response.json()期望一个JSON字符串时,就会发生这种情况。确保你的API以JSON格式返回响应主体。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接