Nuxt 3 SSR:useFetch()在页面刷新时返回null



(在多次编辑我的原始问题后,我决定彻底修改它,使其更加清晰简洁。这符合StackOverflow的建议。)

设置:

创建一个新的Nuxt 3项目:

pnpm dlx nuxi init test-project
cd test-project
pnpm i
pnpm run dev -o

像这样编辑app.vue

<script setup>
const { data: thing } = useFetch("http://localhost:8000/things/1").then(res => {
console.log(res)
return res
})
</script>
<template>
<div>
<p>{{ thing }}</p>
</div>
</template>

我添加了console.log语句来跟踪抓取发生的位置。

未对配置进行任何更改。据我所知,Nuxt 3默认为SSR。

问题:

两种情况:

I。当对app.vue中的代码进行更改并因此触发HMR时,thing将包含来自API的预期数据。

II。但是,在浏览器中刷新页面时,thing将为空。段落标记将为空。

我的观察结果:

  • useAsyncData()也有同样的行为
  • 每次我触发HMR(场景一),客户端都会向API并成功接收数据(如开发者工具的网络选项卡)
  • 每当我在浏览器中刷新页面时(场景II.),我都会在终端和浏览器控制台中收到一个控制台日志。二者都包含一个状态码为500的错误;fetch failed()";。但是,根据网络选项卡,没有客户端请求已制作
  • 如果我改为使用$fetch,它会将相同的错误记录到航空站然而,当请求在服务器端失败时,它会在客户端成功重试,因此API数据将显示在页面上

到目前为止我的结论:

在我看来,所有服务器端请求都失败了,所有客户端请求都成功了。

$fetch在服务器端失败时,它会抛出一个错误并在客户端重试。这正是我所期望的。然而,useFetchuseAsyncData并没有这样的行为。相反,错误被写入响应对象,并且不会发出客户端请求。(不过这不是一个大问题,因为我可以检查响应对象中的错误条目,并在需要时在客户端上发出另一个请求。)

开放式问题:

为什么所有服务器端请求都失败我知道Nuxt服务器无法访问浏览器,因此无法访问cookie等。但这些都是对本地托管的Laravel API的简单GET请求,不需要身份验证。他们不需要CSRF或会话cookie就能成功。我可以在没有cookie的情况下使用Postman成功请求API路由。

这是因为我做错了什么吗?或者这是开发模式下的预期行为(pnpm run dev)我从来没有遇到过Nuxt 2的问题。

恐怕我错过了一些显而易见的东西。

谢谢

wire417。

尝试将您的API地址从"更改为";localhost";至";127.0.0.1";正在使用Fetch请求。它可能会对你有所帮助。

[更新节点]

我得到了和你一样的错误,我的API没有被保护和完全公开,但也无法在SSR页面加载上获得数据。

我花了1天的时间来搜索错误,但也许这就是解决我问题的方法,希望它能帮助你:

在此处更新最新的NodeJS LTS版本:https://nodejs.org/en/

我将NodeJS版本从18.12更新到18.13。我的问题完全解决了。

我在nuxtjs v3.1.2(当前版本)中遇到了同样的问题。这似乎确实是一个时间问题。我通过在nextTick函数中包装useFetch函数来实现它:

export default {
mounted(): {
this.$nextTick(async () => {
const {data, pending, error, refresh } = await useFetch('/...')
}
}

或者如果您正在使用脚本设置

<script setup>
import { nextTick } from 'vue'
await nextTick()
const {data, pending, error, refresh } = await useFetch('/...')
</script>

我在nuxt 3中遇到了完全相同的问题使用nextTik解决您的问题。

<script setup>
import { nextTick } from 'vue'
onMounted(() => {
nextTick(async () => {
const { data } = await useFetch("/data", { baseURL: "http://localhost:8000/api" })
//
})
})
</script>

以下是如何使用nextTik:解决问题的示例

onMounted(() => {
nextTick(async () => {
const { data } = await useFetch("/services", { baseURL: "http://localhost:8000/api" })
services.value = data.value.services
})
})

注意,我使用的是composition api。

尝试切换到Node v16。

我已经和同样的问题斗争了两天了——useFetch()useAsyncData()只有在我通过在nuxt.config.ts中设置ssr: false来关闭SSR的情况下才能工作,否则它会在页面加载时返回null。我使用的是当前最新的Node版本,尝试了最新的LTS版本,但也不起作用。这里的答案都无济于事。然后我决定尝试在Node v16下运行它,它就像一个魅力。一些在线资源表示,Nuxt 3与Node v14或v16配合得最好,顺便说一句,Nuxt 2似乎也是如此。

确保您的api是可访问的。您可以添加const { data, error } = useFetch(...)来查看会发生什么。

nuxt 3.0.0仍然可以与您的应用正常工作

我也遇到过同样的问题,我确实尝试了一些变通方法,比如设置超时或任意使用Fetch()(正如Turukawa在评论中所建议的),但成功率仍然各不相同。

我确实发现使用$fetch似乎是稳定的,并且可以像预期的那样工作。

编辑:我也尝试过更新到Node v 18.13.0,但它没有解决这个问题。

检查api是否可以通过节点访问,而不是通过浏览器或邮递员访问。我在使用ssr时遇到了完全相同的问题。该问题是由于节点ssl错误UNABLE_to_VERIFY_LEAF_SIGNATURE造成的。我修好后,它开始按预期工作。

const { data: data } = await useFetch('https://api.your-domain.com/content/1', {
onRequestError({ request, options, error }) {
// Handle the request errors
console.log(error); // check if there are any errors in the terminal
},
})
console.log(data.data); // this was undefined due to the node cert error

我将节点版本降级为16,令人惊讶的是,它开始按预期工作。在那之前,我认为这是我做过或搞砸的事情。我挣扎了很长时间,说我几乎尝试了阳光下的所有其他东西,这也是它可能不起作用的原因之一,但我不知道为什么。我的操作系统是Windows btw.

据我所知,Vue的Suspense功能在Nuxt3中存在一个问题(对我来说,与转换结合在一起),这里有一个很大的线索https://github.com/nuxt/nuxt/issues/13471和Vue core的公关https://github.com/vuejs/core/pull/5952

在等待修复的过程中,有不同类型的解决方案,我在我的onMounted钩子中使用nextTick(正如Youssef El gharib和Farzad Jafari所建议的),它为我完成了这项工作,希望很快能得到官方修复。有人在这里做了一个可堆肥的变通办法https://github.com/nuxt/nuxt/issues/13471#issuecomment-1449898517

您的代码在JavaScript语法中没有多大意义。

你试图用const { data: thing } = useFetch("http://localhost:8000/things/1").then(res => { console.log(res) return res })'解构一个承诺

此代码将起作用:

<script setup>
const { data: thing } = await useFetch("/things/1")
</script>
<template>
<div>
<p>{{ thing }}</p>
</div>
</template>

看起来手表内部的刷新方法Effect完成的工作

const { data: res, refresh } = await useFetch<IApiResult<ISite>>(`${url}/api/sites/${route.params.routename}`)
const site = computed<ISite|undefined>(() => res.value?.data)
watchEffect(() => {
// maybe could add some sort of req success validation
if(!site.value) refresh()
})

相关内容

  • 没有找到相关文章

最新更新