fetch返回SyntaxError: JSON中的位置0处有意外的T符号。

5

我正在尝试使用JavaScript的fetch方法,但是它似乎不是异步的。

这是我的代码:

fetch(`${global.URL}${url}`, requestConfig)
  .then(res => res.json())
  .then(res => {
    console.log('response', res);
    return res;
  })
  .catch(error => {
    console.log('error: ', error)
  })

我大部分时间都会遇到以下错误,错误率约为70%,但有30%的情况下会收到有效的响应。当我保存文件并重新渲染时,它有时会正常工作。

error:  SyntaxError: Unexpected token T in JSON at position 0
    at parse (<anonymous>)
    at tryCallOne (core.js:37)
    at core.js:123
    at JSTimers.js:277
    at _callTimer (JSTimers.js:135)
    at _callImmediatesPass (JSTimers.js:183)
    at Object.callImmediates (JSTimers.js:446)
    at MessageQueue.__callImmediates (MessageQueue.js:396)
    at MessageQueue.js:144
    at MessageQueue.__guard (MessageQueue.js:373)

我尝试在内部和async/await函数中调用它,但没有帮助。
编辑1:
这是我发出请求的方式。
const authenticityToken = global.TOKEN

const query = (url, config) => {
  const requestConfig = {
    credentials: 'same-origin',
    ...config,
    headers: {
      'X-Requested-With': 'XMLHttpRequest',
      'Content-Type': 'application/json',
      Accept: 'application/json',
      Authorization: authenticityToken,
    },
  }

  return fetch(`${global.URL}${url}`, requestConfig)
  .then(res => res.json())
  .then(res => {
    console.log('response', res);
    return res;
  })
  .catch(error => {
    console.log('error: ', error)
  })
  // .then(handleResponseError)
}

export const get = (url, data) =>
  query(data ? `${url}?${stringify(data)}` : url)

export function fetchUser() {
  return (
    get('/api/v3/me/')
  )
}

然后我在组件中调用该函数,如下所示:
  const fetchUserAction = () => {
    fetchUser()
    .then((response) => {
      if(response) setUser(response.data)
    })
  }

  useEffect(() => {
    fetchUserAction()
  }, [])

3
网络面板显示的响应是什么?每次出错时,响应中是否包含有效的JSON数据? - Panther
当代码出现问题时,我看不到具体情况,因为会触发 catch 语句,只有错误信息被记录在控制台中。 - Hugo
3
在这里记录日志。.then(res => { console.log({res}); return res.json()})。 (注:该代码片段是JavaScript中Promise的语法,.then()用于在Promise成功时执行特定操作,而console.log()用于在控制台打印消息,res.json()则将响应转换为JSON格式。) - Eric Hasselbring
2
那肯定不像是JSON格式。你的问题出在服务器端。 - Pointy
2
嗯...看起来你得到了401,这意味着它是“未经授权的”。因此,你将无法获得有效的响应。解决为什么会随机提供401并继续前进。 - Panther
显示剩余5条评论
3个回答

9
这种类型的错误通常发生在您的服务器返回的内容不是JSON格式时。根据我的经验,99%的情况下,服务器返回的都是通用的错误信息。通常情况下,服务器会有一个通用的“万能”错误处理程序,返回类似下面的内容:
There was an error processing your request.

在这种情况下,如果您尝试使用JSON.parse(或在您的情况下是res.json()),您将遇到您正在经历的错误。要查看此错误,请将以下内容粘贴到控制台中:
JSON.parse("There was an error processing your request.")
//-> Uncaught SyntaxError: Unexpected token T in JSON at position 0

解决方案1:通常服务器在出现错误时会设置适当的状态码。在解析之前,请确保响应状态为200:

fetch('...').then(res => {
  if (res.status !== 200) {
    throw new Error(`There was an error with status code ${res.status}`)
  }
  return res.json()
)

方案2:更新服务端代码,以JSON格式返回错误信息。如果你正在使用Node和Express,代码应该如下所示:
function errorHandler (err, req, res, next) {
  if (res.headersSent) return next(err)

  const message = 'There was an error processing your request.'
  res.status(500)
  if (req.accepts('json')) {
    // The request contains the "Accept" header with the value "application/json"
    res.send({ error: message });
    return;
  }
  res.send(message);
}

接下来,您需要相应地更新前端代码:

fetch('...')
.then(res => res.json())
.then(res => {
  if (res.error) {
    throw new Error(res.error)
  }
  return res
)

5
这种错误Unexpected token T in JSON at position 0通常发生在您尝试解析的字符串无法被解析为JSON时。这个特定的错误意味着字符串以字符“T”开头,而不是像可以解析为JSON的字符串一样以“{”开头。有一个非常严格的格式可以使您的字符串变成一个对象。
如果您确保后端代码接受对象,将其字符串化并发送文本,则可能不是问题所在。如果您知道后端唯一可以发送的内容是一个已经字符串化的对象,那么就没有什么问题了。
第二个更有可能的答案是您的请求失败了。我看到您准备了一个捕获块以防请求返回错误,但其中存在一个问题。请求可能因为多种原因而失败,如果您说它只有在某些情况下才会发生,那么可能是CORS问题或后端逻辑错误。在这种情况下,您希望查看响应本身而不是已解析的响应。实际上的情况是,当请求成功时,主体会成功解析为一个对象,一切正常。但是,当请求失败时,响应将是一个以T开头的异常,例如TimeoutException,当您尝试解析它时失败,因为它以T而不是JSON开头。您需要查看未解析为JSON的响应,只有在它不是错误时,您才应该尝试解析它。
您的代码问题在于您的第一件事就是尝试将其解析为JSON。我建议您注释掉此行,并简单打印成功的请求或失败的请求作为字符串。我非常确定你会发现,在70%的时间里,你会看到你期望的JSON字符串,而在剩下的30%中,你会得到一个异常字符串(甚至可能是由您的后端托管服务自动抛出的,比如Timeout异常,它们可能不被视为错误而被视为字符串。这很不幸,在Firebase函数的免费计划中经常发生,函数运行的时间限制为一定的秒数,在他们的网站上检查计划描述)。这几乎肯定会通过提供更多信息来帮助您找到问题所在。
另外,我强烈建议您停止使用then和catch,而改用远优于它们的async/await语法,这有助于保持代码简单和有组织性。如果它与您针对的所有引擎兼容,请阅读Mozilla的文档,它非常简单:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function 祝您愉快并享受编码的乐趣。

0
尝试这个方法

const response = await fetch('https://apitest.authorize.net/xml/v1/request.api', {
    method: 'post',
    body: JSON.stringify(jsonBody),
    headers: new Headers({'content-type': 'application/json',Accept: 'application/json',}),
    
});

const text = await response.text();
console.log(text);
   

return new Response(text, { status: 200, statusText: 'OK', headers: { 'Content-Type': 'application/json' } });


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