N
Nuxt3w ago
Yuri

Headers aren't available in asyncData

Hello. I have an old project on Nuxt 2. It works as SPA. I have plagin
{ src: '~/plugins/nuxt-client-init.ts', ssr: false, }
import { Context } from "~/node_modules/@nuxt/types";

export default async (ctx: Context) => {
const nuxtServerInitResponse = await ctx.store.dispatch('nuxtServerInit', ctx)
if(nuxtServerInitResponse.token) {
ctx.$axios.setToken(nuxtServerInitResponse.token)
console.log('[PLUGIN] token is installed:', ctx.$axios.defaults.headers.common.Authorization)
}
}
import { Context } from "~/node_modules/@nuxt/types";

export default async (ctx: Context) => {
const nuxtServerInitResponse = await ctx.store.dispatch('nuxtServerInit', ctx)
if(nuxtServerInitResponse.token) {
ctx.$axios.setToken(nuxtServerInitResponse.token)
console.log('[PLUGIN] token is installed:', ctx.$axios.defaults.headers.common.Authorization)
}
}
And I have page/index.vue
@Component
})
export default class pageIndex extends mixins(MixinGeneral) {
private async asyncData({
$axios,
error,
}: {
$axios: NuxtAppOptions
route: NuxtAppOptions
error: any
}) {
try {
console.log('[ASYNCDATA] token:', $axios.defaults.headers.common.Authorization)
const response = await $axios.$get(filterUrl(INDEX_API))

return response
} catch (err) {
error({ statusCode: 404, message: 'Post not found' })
}
}
@Component
})
export default class pageIndex extends mixins(MixinGeneral) {
private async asyncData({
$axios,
error,
}: {
$axios: NuxtAppOptions
route: NuxtAppOptions
error: any
}) {
try {
console.log('[ASYNCDATA] token:', $axios.defaults.headers.common.Authorization)
const response = await $axios.$get(filterUrl(INDEX_API))

return response
} catch (err) {
error({ statusCode: 404, message: 'Post not found' })
}
}
I receive in the console:
[PLUGIN] token is installed: 3qGikvMGmonyGj7e0czIzMOf0UEmlg
[ASYNCDATA] token: undefined
[PLUGIN] token is installed: 3qGikvMGmonyGj7e0czIzMOf0UEmlg
[ASYNCDATA] token: undefined
Token is recieved in nuxtServerInit. Why is the token in ASYNCDATA is unavailable? What can I do to make sure the token is available when the request in asyncData executed?
8 Replies
kapa.ai
kapa.ai3w ago
Hi @Yuri. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave: ---------------------- The issue you're experiencing is related to the execution order in Nuxt 2. In your SPA mode application, the asyncData hook is running before your client-side plugin has a chance to set the token. Why this happens In Nuxt 2, when running in SPA mode: 1. The asyncData hook runs on initial page load before client-side plugins 2. Your nuxt-client-init.ts plugin (which sets the token) runs after the initial asyncData call This explains why you see:
[ASYNCDATA] token: undefined
[PLUGIN] token is installed: 3qGikvMGmonyGj7e0czIzMOf0UEmlg
[ASYNCDATA] token: undefined
[PLUGIN] token is installed: 3qGikvMGmonyGj7e0czIzMOf0UEmlg
Solutions You have a few options to solve this: Option 1: Move token setting to a middleware Create a middleware that runs before your page components and sets the token:
// middleware/auth.js
export default async function ({ store, $axios }) {
const response = await store.dispatch('nuxtServerInit')
if (response.token) {
$axios.setToken(response.token)
}
}
// middleware/auth.js
export default async function ({ store, $axios }) {
const response = await store.dispatch('nuxtServerInit')
if (response.token) {
$axios.setToken(response.token)
}
}
Then use this middleware in your page:
@Component({
middleware: ['auth']
})
export default class pageIndex extends mixins(MixinGeneral) {
// ...
}
@Component({
middleware: ['auth']
})
export default class pageIndex extends mixins(MixinGeneral) {
// ...
}
Option 2: Handle token absence in asyncData Modify your asyncData to check for token and fetch it if needed:
private async asyncData({
$axios,
store,
error,
}: {
$axios: NuxtAppOptions
store: any
error: any
}) {
try {
// Check if token exists, if not, get it
if (!$axios.defaults.headers.common.Authorization) {
const response = await store.dispatch('nuxtServerInit')
if (response.token) {
$axios.setToken(response.token)
}
}

const response = await $axios.$get(filterUrl(INDEX_API))
return response
} catch (err) {
error({ statusCode: 404, message: 'Post not found' })
}
}
private async asyncData({
$axios,
store,
error,
}: {
$axios: NuxtAppOptions
store: any
error: any
}) {
try {
// Check if token exists, if not, get it
if (!$axios.defaults.headers.common.Authorization) {
const response = await store.dispatch('nuxtServerInit')
if (response.token) {
$axios.setToken(response.token)
}
}

const response = await $axios.$get(filterUrl(INDEX_API))
return response
} catch (err) {
error({ statusCode: 404, message: 'Post not found' })
}
}
Option 3: Use fetch hook instead of asyncData In Nuxt 2, the fetch hook runs after the component is created, which means it will run after your plugin in SPA mode:
@Component({})
export default class pageIndex extends mixins(MixinGeneral) {
data = null;

async fetch() {
try {
console.log('[FETCH] token:', this.$axios.defaults.headers.common.Authorization)
this.data = await this.$axios.$get(filterUrl(INDEX_API))
} catch (err) {
this.$nuxt.error({ statusCode: 404, message: 'Post not found' })
}
}
}
@Component({})
export default class pageIndex extends mixins(MixinGeneral) {
data = null;

async fetch() {
try {
console.log('[FETCH] token:', this.$axios.defaults.headers.common.Authorization)
this.data = await this.$axios.$get(filterUrl(INDEX_API))
} catch (err) {
this.$nuxt.error({ statusCode: 404, message: 'Post not found' })
}
}
}
This issue is related to the execution order of hooks and plugins in Nuxt, which is something that has been improved in Nuxt 3 with composables like useAsyncData and better handling of request headers. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai3w ago
<@740173469404364872> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
Yuri
YuriOP3w ago
@kapa.ai I have a lot of pages with useAsyncData? What is the best and the fastest solution?
kapa.ai
kapa.ai3w ago
Let me check the knowledge base for you again. One moment! :books: ---------------------- Based on your previous question about token availability in Nuxt 2's asyncData, I understand you're now asking about the best and fastest solution for handling useAsyncData across multiple pages, likely in a Nuxt 3 context. Best Practices for useAsyncData When working with multiple pages that use useAsyncData, there are several optimizations and best practices to consider: 1. Use proper key management Always provide unique keys that accurately represent the data being fetched, especially in dynamic pages:
// Good practice - using a key that identifies the specific data
const { data } = await useAsyncData(route.params.slug, async () => {
return await $fetch(`/api/my-page/${route.params.slug}`)
})
// Good practice - using a key that identifies the specific data
const { data } = await useAsyncData(route.params.slug, async () => {
return await $fetch(`/api/my-page/${route.params.slug}`)
})
This is particularly important if you enable shared prerender data optimization as documented here. 2. Avoid awaiting useAsyncData in wrappers A common issue is awaiting useAsyncData inside custom wrapper functions, which can lead to "Nuxt instance unavailable" errors:
// Instead of this pattern in a custom wrapper
async function myWrapper() {
const { data } = await useAsyncData(...) // Can cause issues
}

// Prefer returning the useAsyncData result directly
function myWrapper() {
return useAsyncData(...)
}
// Instead of this pattern in a custom wrapper
async function myWrapper() {
const { data } = await useAsyncData(...) // Can cause issues
}

// Prefer returning the useAsyncData result directly
function myWrapper() {
return useAsyncData(...)
}
This approach is recommended based on recent documentation updates mentioned in this PR. 3. Enable shared prerender data for SSG If you're using Static Site Generation, enable the sharedPrerenderData feature for significant performance improvements:
// nuxt.config.ts
export default defineNuxtConfig({
experimental: {
sharedPrerenderData: true
}
})
// nuxt.config.ts
export default defineNuxtConfig({
experimental: {
sharedPrerenderData: true
}
})
This feature shares payload data between prerendered pages, reducing duplicate fetches as explained here. 4. Use runWithContext for async operations For async operations outside the Vue component lifecycle:
const nuxtApp = useNuxtApp()
await nuxtApp.runWithContext(async () => {
// Your async code using Nuxt composables here
})
const nuxtApp = useNuxtApp()
await nuxtApp.runWithContext(async () => {
// Your async code using Nuxt composables here
})
This approach is recommended for handling async code with Nuxt composables as shown in this YouTube video. 5. Structure your async code properly Make sure your async operations are properly structured:
// Instead of this:
if (authToken.value) {
await useAsyncData(async () => {
fetchData();
});
}

// Do this:
await useAsyncData(async () => {
if (authToken.value) {
await fetchData();
}
});
// Instead of this:
if (authToken.value) {
await useAsyncData(async () => {
fetchData();
});
}

// Do this:
await useAsyncData(async () => {
if (authToken.value) {
await fetchData();
}
});
This pattern has been shown to help with proper server-side execution as demonstrated in this Stack Overflow post. By implementing these practices, you should see improved performance and fewer issues across your pages that use useAsyncData. The most important aspects are proper key management, avoiding awaiting useAsyncData in wrappers, and considering shared prerender data for static sites. Would you like more specific guidance on any of these approaches? ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai3w ago
<@740173469404364872> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
Yuri
YuriOP3w ago
@kapa.ai i'm sorry. I use asyncData in Nuxt 2. I made a mistake in the previous message
kapa.ai
kapa.ai3w ago
Let me check the knowledge base for you again. One moment! :books: ---------------------- I understand now - you're working with Nuxt 2 and using asyncData, not Nuxt 3's useAsyncData. Let me provide a more relevant answer for your Nuxt 2 context. Best Solutions for asyncData in Nuxt 2 Since you mentioned having many pages with asyncData and need the token to be available, here are the most efficient solutions: 1. Use a plugin with the correct order In Nuxt 2, you can control plugin execution order. Make sure your authentication plugin runs before your pages by setting a lower order number:
// nuxt.config.js
export default {
plugins: [
{ src: '~/plugins/auth.js', order: 10 }, // Lower number runs first
{ src: '~/plugins/nuxt-client-init.ts', ssr: false }
]
}
// nuxt.config.js
export default {
plugins: [
{ src: '~/plugins/auth.js', order: 10 }, // Lower number runs first
{ src: '~/plugins/nuxt-client-init.ts', ssr: false }
]
}
2. Create a global middleware A global middleware is one of the most efficient solutions as it runs before all page components:
// middleware/auth.js
export default function ({ store, $axios }) {
// Check if token is already set
if (!$axios.defaults.headers.common.Authorization) {
const token = store.state.auth.token // Adjust based on your store structure
if (token) {
$axios.setToken(token)
}
}
}
// middleware/auth.js
export default function ({ store, $axios }) {
// Check if token is already set
if (!$axios.defaults.headers.common.Authorization) {
const token = store.state.auth.token // Adjust based on your store structure
if (token) {
$axios.setToken(token)
}
}
}
Then register it as a global middleware:
// nuxt.config.js
export default {
router: {
middleware: ['auth']
}
}
// nuxt.config.js
export default {
router: {
middleware: ['auth']
}
}
3. Use a Vuex action for API calls Instead of directly using $axios in your asyncData, create a Vuex action that ensures the token is set before making API calls:
// store/index.js
export const actions = {
async fetchWithAuth({ state, dispatch }, { url, method = 'get', data = null }) {
// Ensure token is set
if (!this.$axios.defaults.headers.common.Authorization && state.auth.token) {
this.$axios.setToken(state.auth.token)
}

// Make the API call
return this.$axios[`$${method}`](url, data)
}
}
// store/index.js
export const actions = {
async fetchWithAuth({ state, dispatch }, { url, method = 'get', data = null }) {
// Ensure token is set
if (!this.$axios.defaults.headers.common.Authorization && state.auth.token) {
this.$axios.setToken(state.auth.token)
}

// Make the API call
return this.$axios[`$${method}`](url, data)
}
}
Then in your components:
async asyncData({ store, error }) {
try {
const response = await store.dispatch('fetchWithAuth', {
url: filterUrl(INDEX_API)
})
return response
} catch (err) {
error({ statusCode: 404, message: 'Post not found' })
}
}
async asyncData({ store, error }) {
try {
const response = await store.dispatch('fetchWithAuth', {
url: filterUrl(INDEX_API)
})
return response
} catch (err) {
error({ statusCode: 404, message: 'Post not found' })
}
}
This approach centralizes your API call logic and token handling, making it easier to maintain across many pages. The global middleware approach (#2) is likely the fastest and most efficient solution if you need to apply this across many pages without changing each component. Would you like more details on any of these approaches? ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai3w ago
<@740173469404364872> Kapa.ai is still learning and improving, please let me know how I did by reacting below.

Did you find this page helpful?